Becoming adept at using the command line interface (CLI) and Bash is one of the most rewarding prospects of being a GNU/Linux user. The initial learning curve is high, but the long-term rewards are manifold.
One of the best aspects of this fluency is the ability to customize the shell environment to fit your needs through various features. For example, Bash offers:
Over time, you may come to rely on your customizations and lament their absence when moving to a new system. Initially, you may have taken some time to optimally configure your shell. Now, you can use the skills that you have acquired to easily initialize a new system's environment.
Note: If you are not familiar with the GNU/Linux command line interface, review the Conventions page before proceeding.
The Setup
A simple way to configure a new system's shell environment is to use shell scripting itself. The solution below assumes the copying of a configuration directory to a new Debian or Fedora GNU/Linux system, where the copied directory has a structure like the following:
$ tree "${HOME}/sh_config/"
/home/amnesia/sh_config/
├── dot_files
│ ├── dbn_bashrc.txt
│ ├── dbn_profile.txt
│ ├── fda_bash_profile.txt
│ ├── fda_bashrc.txt
│ └── vimrc.txt
├── cfg_sh.bash
└── scripts
├── script_1.bash
├── script_2.bash
├── script_3.py
├── script_4.py
└── script_5.sh
2 directories, 11 files
The configuration directory (i.e., /home/amnesia/sh_config/
) contains:
- The shell configuration script (
cfg_sh.bash
). -
A directory of files that serve as the basis for the new system's dot files (
dot_files/
). All files in this directory should be saved with the.txt
extension.Debian and Fedora-specific files are given special prefixes (
dbn_
,fda_
). Distribution-agnostic files (e.g.,vimrc.txt
) do not require a special prefix. -
A directory of scripts (
scripts/
).
Before running the shell configuration script, five variables need to be set:
dot_files_src
The name of the directory that contains the files that serve as the basis for the new system's dot files.deb_prefix
The string prefix that has been chosen to specify files with Debian-specific dot file content.fed_prefix
The string prefix that has been chosen to specify files with Fedora-specific dot file content.scripts_dir_src
The name of the directory that contains the scripts to be copied to the new system.scripts_dir_dest
The destination directory on the new system to copy scripts to.
After the configuration directory is copied to the new system, the shell configuration script is run.
For example, if you saved a sh_config/
configuration directory to the Downloads/
directory of your user's home folder, you could run a cfg_sh.bash
configuration script like so:
bash "${HOME}/Downloads/sh_config/cfg_sh.bash"
Alternatively, you could change to the directory that contains cfg_sh.bash
and issue the following command:
bash './cfg_sh.bash'
If your system passes the script's verification checks, its dot files will incorporate your custom dot file content, the configuration directory's scripts will be copied to the script directory that you specified for your new system, and the scripts will be made executable.
Script and System Preparation
The first parts of the configuration script evaluate the script arguments and ensure that the script's required variables have been set:
parse_args "${@}"
run_init_cks
Above, we evaluate the script's arguments using shell special parameters and a case statement. If help is requested via the use of the -h
(--help
) option or incorrect arguments are provided, usage information is displayed via a call to the display_usage()
function.
Then, we loop through an indexed array of required variable names and check to see if each variable is set using an indirect variable reference (i.e., "${!required_var}"
). Here, an indirect reference is necessary because the required_vars
array contains the string names of variables.
Without an indirect reference, [[ "${required_var}" ]]
would simply check to see if the required_var
variable contains a value, which it always will. By using an indirect reference, we instruct the shell to refer to the variable whose name is assigned to the required_var
variable.
The following example helps illustrate this concept:
$ protagonist='Nightwing'
$ antagonist='Deathstroke'
$ agonist='protagonist'
$ echo "${agonist} rules!"
protagonist rules!
$ echo "${!agonist} rules!"
Nightwing rules!
If a variable is not set, a message with the variable name is displayed, reminding the user to set the variable before attempting to run the script again.
Once the above criteria are met, the script uses the realpath
command and a special parameter to obtain the absolute path of the shell configuration script as it is running on your system:
abs_path="$(realpath "${0}")" # Get absolute path of script
Then, the absolute path of the script configuration directory is extracted from abs_path
using a pattern matching operator:
# Get absolute path of script configuration directory
dir_path="${abs_path%/*}"
Configuration
The rest of the script performs the actual configuration steps for the new GNU/Linux system.
The files in the dot files source directory are looped through and, once processed in a distribution-sensitive way, their content is either added to the new system's equivalent dot file (e.g., .bashrc
) or used to create a new dot file (e.g., .vimrc
).
# Filter out extraneous files, customize command prompt
if grep -iq 'debian' '/etc/os-release'; then
# Loop through each .txt file in dot_files_src
for f in ./${dot_files_src}/*; do
# Filter out Fedora-specific files
if ! [[ "${f}" =~ ${dot_files_src}/${fed_prefix}.+ ]]; then
f_base="${f%.txt}"
# Remove Debian prefix from filename
if [[ "${f_base}" =~ ${dot_files_src}/${deb_prefix}+ ]]; then
f_base="${f_base/${deb_prefix}/}"
fi
# Create file basename
f_base="${f_base##*/}"
# Append file content
cat "${f}" >> "${HOME}/.${f_base}"
fi
done
elif grep -iq 'fedora' '/etc/os-release'; then
for f in ./${dot_files_src}/*; do
if ! [[ "${f}" =~ ${dot_files_src}/${deb_prefix}.+ ]]; then
f_base="${f%.txt}"
if [[ "${f_base}" =~ ${dot_files_src}/${fed_prefix}.+ ]]; then
f_base="${f_base/${fed_prefix}/}"
fi
f_base="${f_base##*/}"
cat "${f}" >> "${HOME}/.${f_base}"
fi
done
else
err_msg='\nUnable to verify supported GNU/Linux '
err_msg+='distribution.\n'
echo -e "${err_msg}" 1>&2
exit 1
fi
Finally, the script destination directory on the new system is created (if applicable) and the scripts are copied over. After the scripts are made executable, a message is displayed to make the configuration script's changes to the new system effective:
pass_or_fail="$(val_extant_dir "${scripts_dir_dest}")"
if [[ "${pass_or_fail}" -ne 0 ]]; then
mkdir "${scripts_dir_dest}" # Create script directory
fi
# Copy over scripts
for f in ${dir_path}/${scripts_dir_src}/*; do
cp -f "${f}" "${scripts_dir_dest}"
done
chmod -R 700 "${scripts_dir_dest}" # Make scripts executable
# Display log out message
echo -e '\nLog out and log back in to see changes take effect.\n'
The full script is available below:
The Virtuous Cycle
Adopting Free/Libre Open Source Software (FLOSS) creates a virtuous cycle. By ensuring the freedoms of its users, individuals and their communities have a chance to use what they learn to further improve FLOSS and their lives.