I have a GitHub repository containing all my dotfiles for bash
, tmux
and neovim
. I'm using a Mac and whenever I factory reset it I like to just pull repository from GitHub and link all the dotfiles to the one in the repo.
Now I wrote a script to automatically create these symlinks and handle possible errors on the way.
This is what I came up with:
#!/usr/bin/env bash
RED=`tput setaf 1`
GREEN=`tput setaf 2`
RESET=`tput sgr0`
custom_link() {
file_loc="$1"
symlink_loc="$2"
# Check whether original file is valid
if [[ ! -e "$file_loc" ]]; then
echo "${RED}WARNING${RESET}: Failed to link $symlink_loc to $file_loc"
echo " $file_loc does not exist"
return 1
fi
# Check whether symlink already exists
if [[ -e "$symlink_loc" ]]; then
if [[ -L "$symlink_loc" ]]; then
if [[ "$(readlink $symlink_loc)" == "$file_loc" ]]; then echo "--> $symlink_loc -> $file_loc ${GREEN}exists${RESET}."; return 0; fi
current_dest=$(readlink "$symlink_loc")
echo "It seems like $symlink_loc already is symlink to $current_dest."
read -p "Do you want to replace it? [Y/N] " -n 1 -r
if [[ $REPLY =~ ^[Yy]$ ]]
then
echo
echo "Removing current symlink..."
unlink $symlink_loc
ln -s "$file_loc" "$symlink_loc"
echo "Created a symlink $symlink_loc -> $file_loc"
return 0
fi
echo
return 2
else
echo "It seems like $symlink_loc already exists."
read -p "Do you want to [d]elete, [m]ove (-> $HOME/.other/) or [k]eep $symlink_loc? " -n 1 -r
if [[ $REPLY =~ ^[Dd]$ ]]
then
printf "\nDeleting $symlink_loc..."
rm -rf "$symlink_loc"
ln -s "$file_loc" "$symlink_loc"
echo "Created a symlink $symlink_loc -> $file_loc"
return 0
elif [[ $REPLY =~ ^[Mm]$ ]]; then
printf "\nMoving $symlink_loc to ~$HOME/.other..."
mkdir "$HOME/.other"
mv "$symlink_loc" "$HOME/.other"
ln -s "$file_loc" "$symlink_loc"
echo "Created a symlink $symlink_loc -> $file_loc"
return 0
else
printf "\nKeeping $symlink_loc...\n"
return 2
fi
fi
fi
symlink_dir=$(dirname "$symlink_loc")
if ! mkdir -p "$symlink_dir" ; then
echo "${RED}WARNING${RESET}: Failed to link $symlink_loc to $file_loc"
echo " Could not create folder $symlink_dir/"
return 1
fi
ln -s "$file_loc" "$symlink_loc"
echo "Created a symlink $symlink_loc -> $file_loc"
return 0
}
custom_link "$HOME/.dotfiles/bash/.bashrc" "$HOME/.bash_profile"
custom_link "$HOME/.dotfiles/bash/.bashrc" "$HOME/.bashrc"
custom_link "$HOME/.dotfiles/nvim/init.vim" "$HOME/.config/nvim/init.vim"
custom_link "$HOME/.dotfiles/tmux/.tmux.conf" "$HOME/.tmux.conf"
It was my very first time writing a bash script and I just googled, whenever I had a specific question.
I choose the return codes as follows:
- 0
for successful creation
- 1
for failure
- 2
for cases, when the link was not created, because the user decided so.
My questions are:
- How is my general bash programming style? Any important idioms I missed?
- The script contains a lot of duplicate code (especially the three lines:
ln -s "$file_loc" "$symlink_loc"
,echo "Created a symlink $symlink_loc -> $file_loc"
andreturn 0
. How can I reduce the number of duplicates? - How could I implement more successful return values?
- I handles a lot of cases (the file already exists, etc.). Did I miss any important cases?
- Currently the function
custom_link
displays a lot of text. How could I outsource this echoing to the outside of the function? The function should do the bare minimum (maybe connected to the question about useful return codes).