# Shell script that creates and deletes symbolic links

Right now I am working on an install and uninstall script for my vim configuration files. The install script links files and directories and the uninstall script deletes those links. I just want to make sure that this code is somewhat safe, are there better ways of doing the same thing? Here is the code I have right now:

Install Script:

#!/bin/bash
# The install script for my vim dotfiles.
# Find the location of the script.
SCRIPT_DIRECTORY="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # The source directory and target directories. SOURCE_LOCATION="$SCRIPT_DIRECTORY/src" # Contains the files and directories I want to work with.
TARGET_LOCATION="$SCRIPT_DIRECTORY/test-home" # The location I want to link to, in production this would be "~/" # Link the files from source to the target with a dot appended to the front. find$SOURCE_LOCATION -mindepth 1 -maxdepth 1 -printf "%P\n" | while read file; do
echo "Linking $SOURCE_LOCATION/$file to $TARGET_LOCATION/.$file"
ln -s "$SOURCE_LOCATION/$file" "$TARGET_LOCATION/.$file"
done


Uninstall Script:

#!/bin/bash
# The uninstall script for my vim dotfiles.
# Find the location of the script.
SCRIPT_DIRECTORY="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # The source directory and target directories. SOURCE_LOCATION="$SCRIPT_DIRECTORY/src" # Contains the files and directories I want to work with.
TARGET_LOCATION="$SCRIPT_DIRECTORY/test-home" # The location I want to link to, in production this would be "~/" # Remove the links the install script would create. find$SOURCE_LOCATION -mindepth 1 -maxdepth 1 -printf "%P\n" | while read file; do
echo "Removing $TARGET_LOCATION/.$file"
rm -I "$TARGET_LOCATION/.$file"
done


If you're worried about it being safe, probably verifying that what you're deleting is a symlink and bailing out if not would be a good start:

if [[ ! -h $TARGET_LOCATION/.$file ]]; then
printf >&2 "%s is not a symlink!\n" "$TARGET_LOCATION/.$file"
return 1
fi


Also, your deploy script doesn't seem to much care if there are existing .vim/.vimrc files to deal with, so I have to wonder: why bother juggling the configs? If there's any possibility someone else's config will be there, best check for it

if [ -e "$TARGET_LOCATION/.$file" ]; then
printf >&2 "%s exists, cowardly refusing to clobber it\n" "$TARGET_LOCATION/.$file"
return 1
fi


You might also consider placing this at the top of your script:

set -e


This will cause your script to cease execution immediately if any command in the pipe returns a non-0 status and isn't caught by an explicit check (if/then, &&/||, etc -- see manpage for the gory details). Generally, I recommend to always write shell with this on, but especially so if you're doing something you're nervous will misbehave.

SCRIPT_DIRECTORY="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"  Is that how you are getting an absolute path? I would be cautious, if for some reason that command fails, even set -e won't catch it (launched in a subshell), then you have an unset$SCRIPT_DIRECTORY. That may cause find to fail, but it might cause it to walk your CWD, too.. hard to tell at a glance. I personally use a set of functions I tote around that do path normalization and has proper abspath() function to use, but in the interest of keeping this simple, consider skipping the clever tricks and set an explicit path (assuming it's not going to be changing). If that's not an option, I would add a sanity check to make sure what I'm walking and copying is what I expect. This can be as simple as checking a file is there that wouldn't be in ~ already.
And just throwing this out there: Consider making your dotfiles permanent but with a different name, then use an alias/function to set the desired config, e.g.: myvim () { vim -u "$HOME/.my.vimrc" "$@"; }. Not sure of your situation, but it might be more pleasant/less sketchy way to handle it.