#! /bin/bash # # Symlink a existing file to a new location. Rename and link to old versions with datestamps. # # usage: link2 [options] target [link] # -v | --vrebose Echo command names # -d | --debug Additional debugging output # -h | --help This text # -n | --dry-run Do not execute # -r | --remove Remove link/file if it exists # # Examples: # # $ link2 -v /etc/passwd # ln -s /etc/passwd /home/george/bin/passwd # # $ link2 -v /etc/issue passwd # mv passwd passwd.20150609:052604EDT # ln -s /etc/issue passwd # # $ link2 -r -v /etc/issue passwd # link2: passwd already points to /etc/issue # # $ link2 -r -v /etc/issue passwd # rm -f passwd # ln -s /etc/issue passwd # # $ link2 -v /etc/passwd $HOME # ln -s /etc/passwd /home/george/passwd # # # Author: # George Jones set -e -u PROG_NAME=$0 PROG_NAME=`basename $0` SHORT_OPTS='vdhnrs:' LONG_OPTS='verbose,debug,dry-run,help,remove,stack-size:' OPTS=`getopt -o $SHORT_OPTS --long $LONG_OPTS -n 'parse-options' -- "$@"` function usage() { cat <&2 usage: $PROG_NAME [options] target [link] -v | --verbose Echo command names -d | --debug Additional debugging output -h | --help This text -n | --dry-run Do not execute -r | --remove Remove link/file if it exists END exit 1 } if [ $? != 0 ] ; then echo "Failed parsing options." >&2 ; exit 1 ; fi eval set -- "$OPTS" # Default values VERBOSE=false HELP=false DRY_RUN=false STACK_SIZE=0 DEBUG=false REMOVE=false # Set user selected options while true; do case "$1" in -v | --verbose ) VERBOSE=true; shift ;; -d | --debug ) DEBUG=true; shift ;; -h | --help ) HELP=true; shift ;; -n | --dry-run ) DRY_RUN=true; shift ;; -r | --remove ) REMOVE=true; shift ;; -s | --stack-size ) STACK_SIZE="$2"; shift; shift ;; -- ) shift; break ;; * ) break ;; esac done if $DEBUG; then VERBOSE=true fi if $DEBUG; then echo VERBOSE=$VERBOSE echo DEBUG=$DEBUG echo HELP=$HELP echo DRY_RUN=$DRY_RUN echo REMOVE=$REMOVE echo STACK_SIZE=$STACK_SIZE fi # validate arguments if [[ "$STACK_SIZE" =~ '"^[0-9]+$' ]]; then echo "$PROG_NAME: stack_size must be an integer. Got /$STACK_SIZE/" >&2 usage fi # get file arguments if [ "$#" -lt 1 ]; then echo $PROG_NAME: Missing target usage fi if $HELP; then usage fi file=$1 whereto=${2:-"${PWD}"} # figure out the link target, make sure it exists target="`readlink -f $file`" if $DEBUG; then echo target $target; fi if [ ! -e ${target} ]; then echo $0: ${target} does not exist >&2 exit 1 fi # figure out the link source, using basename of target base=`basename $file` if [ -d `readlink -f "${whereto}"` ]; then link="${whereto}""/""${base}" else link=${whereto} fi # Remove link if it exists if $REMOVE && [ -h $link -o -f $link ]; then if $DRY_RUN || $VERBOSE; then echo rm -f $link fi if ! $DRY_RUN; then rm -f $link fi fi # move any pre-existing file to a dated save version, unless it's the same now=`date "+%Y%m%d:%H%M%S%Z"` if [ -e ${link} ]; then # TODO abort here if target already points to target. expandedLink=`readlink -e ${link}` expandedTarget=`readlink -e ${target}` if [ ${expandedLink} == ${expandedTarget} ]; then echo $PROG_NAME: ${link} already points to ${target} >&2 exit 0 fi if $DRY_RUN || $VERBOSE; then echo mv ${link} "${link}.${now}" fi if ! $DRY_RUN; then mv ${link} "${link}.${now}" fi fi # finally, make the link if $DEBUG; then echo target $target >&2; fi if $DRY_RUN || $VERBOSE; then echo ln -s ${target} ${link} fi if ! $DRY_RUN; then ln -s ${target} ${link} fi