Recursive symbolic link creation script
This might be useful if you keep your settings (.bashrc
,
.subversion/config
, etc.) outside the home directory, like in a
Subversion repository. Just copy the following script to the repository
directory corresponding to $HOME and run
/path/to/make-links.sh
to create symlinks from ~
to each file in the repository,
recursively.
If you don't want to use meld to see
differences, just change the diff
variable near the top of the
code.
Edit 2: Now actually does something useful if the target file already exists or the target directory does not exist.
make-links.sh
#!/bin/sh
#
# $Id: make-links.sh 1870 2009-11-10 08:56:35Z vengmark $
#
# NAME
# make-links.sh - Make symlinks to all user settings in repository
#
# SYNOPSIS
# make-links.sh [options]
#
# OPTIONS
# -v,--verbose Verbose output
# -d Specify the source and target directories for the symlinks
#
# EXAMPLE
# /path/to/make-links.sh -d ~/settings/user ~
#
# Create links in the home directory based on files in ~/settings/user
#
# /path/to/make-links.sh -v
#
# Create links in / based on files in the directory of make-links.sh
#
# DESCRIPTION
# If the file in the source directory doesn't exist in the target directory,
# a symlink is created directly.
# If the file exists, or the target directory does not exist, the user is
# given options to continue.
#
# BUGS
# Email bugs to victor dot engmark at gmail dot com. Please include the
# output of running this script in verbose mode (-v).
#
# COPYRIGHT AND LICENSE
# Copyright (C) 2008-2009 Victor Engmark
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
# Output error message
error()
{
if [ -z "$2" ]
then
error_code=$EX_UNKNOWN
else
error_code=$2
fi
echo "$1" >&2
exit $error_code
}
usage()
{
error "Usage: ${cmdname} [-v|--verbose] [-d source target]" $EX_USAGE
}
verbose_echo()
{
if [ $verbose ]
then
echo "$*"
fi
}
# Use for mandatory directory checks
# $1 is the directory path
# $2 is the (optional) error message
directory_exists()
{
if [ ! -d $1 ]
then
error "No such directory '${1}'
$2" $EX_NO_SUCH_DIR
fi
}
# Make sure an executable is available
# $1 is the path to the executable
# $2 is the (optional) error message
executable_exists()
{
if [ ! -x $1 ]
then
error "No such executable '${1}'
$2" $EX_NO_SUCH_EXEC
fi
}
ifs_original="$IFS" # Reset when done
IFS="
" # Make sure paths with spaces don't make any trouble when looping
PATH="/usr/bin:/bin"
cmdname=`basename $0`
directory=$(dirname $(readlink -f $0))
diff=/usr/bin/meld
source_base="${directory}/home/$(whoami)/"
target_base="$HOME"
# Exit codes from /usr/include/sysexits.h, as recommended by
# http://www.faqs.org/docs/abs/HTML/exitcodes.html
EX_OK=0 # successful termination
EX_USAGE=64 # command line usage error
EX_DATAERR=65 # data format error
EX_NOINPUT=66 # cannot open input
EX_NOUSER=67 # addressee unknown
EX_NOHOST=68 # host name unknown
EX_UNAVAILABLE=69 # service unavailable
EX_SOFTWARE=70 # internal software error
EX_OSERR=71 # system error (e.g., can't fork)
EX_OSFILE=72 # critical OS file missing
EX_CANTCREAT=73 # can't create (user) output file
EX_IOERR=74 # input/output error
EX_TEMPFAIL=75 # temp failure; user is invited to retry
EX_PROTOCOL=76 # remote error in protocol
EX_NOPERM=77 # permission denied
EX_CONFIG=78 # configuration error
# Custom errors
EX_UNKNOWN=1
EX_NO_SUCH_DIR=91
EX_NO_SUCH_EXEC=92
# Process parameters
until [ $# -eq 0 ]
do
case $1 in
-v|--verbose)
verbose=1
shift
;;
-d)
if [ -z "$2" ] || [ -z "$3" ]
then
usage_error
fi
source_base=$2
target_base=$3
shift 3
;;
*)
# Unknown parameter
usage
;;
esac
done
verbose_echo "Running $cmdname at `date`."
# Make sure the directory paths don't end with a slash
source_base="${source_base%\/}"
target_base="${target_base%\/}"
# Preliminary checks
directory_exists "$source_base"
directory_exists "$target_base"
verbose_echo "Source directory: '${source_base}'"
verbose_echo "Target directory: '${target_base}'"
# Find files excluding .svn directories
for source_path in `find "$source_base" -mindepth 1 -type f | grep -v "/.svn/"`
do
target_path="${target_base}${source_path#${source_base}}"
target_dir="$(dirname "${target_path}")"
unset replace_file
unset create_dir
verbose_echo ""
verbose_echo "Source file: \"${source_path}\"."
verbose_echo "Target file: \"${target_path}\"."
# Trivial case
if [ -L "$target_path" ]
then
verbose_echo "\"${target_path}\" is already a symlink; skipping."
continue
fi
# File exists
if [ -f "$target_path" ]
then
# Make sure we skip or replace in the end
while ! expr "$replace_file" : "^[SsRr]$" > /dev/null
do
echo "\"${target_path}\" is a proper file. What do you want to do?"
read -p "[S]kip, [D]iff, [R]eplace: " replace_file
if expr "$replace_file" : "^[Dd]$" > /dev/null
then
verbose_echo "Diffing \"${source_path}\" and \"${target_path}\""
$diff "$source_path" "$target_path"
fi
done
if expr "$replace_file" : "^[Rr]$"
then
verbose_echo "Removing ${target_path}"
rm "$target_path"
else
continue
fi
fi
# Not a proper file
if [ -e "$target_path" ]
then
echo "\"${target_path}\" exists but is not a file; skipping."
continue
fi
# Directory missing; might have to create it
if [ ! -e "$target_dir" ]
then
while ! expr "$create_dir" : "^[SsCc]$" > /dev/null
do
echo "\"${target_dir}\" doesn't exist. What do you want to do?"
read -p "[S]kip or [C]reate: " create_dir
done
if expr "$create_dir" : "^[Cc]$" > /dev/null
then
mkdir -p "$target_dir"
else
continue
fi
fi
echo "Creating symlink at \"${target_path}\"."
ln -s "$source_path" "$target_path"
done
verbose_echo "Cleaning up."
IFS="$ifs_original"
verbose_echo "${cmdname} completed at `date`."
exit $EX_OK
No webmentions were found.