link2 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #! /bin/bash
  2. #
  3. # Symlink a existing file to a new location. Rename and link to old versions with datestamps.
  4. #
  5. # usage: link2 [options] target [link]
  6. # -v | --vrebose Echo command names
  7. # -d | --debug Additional debugging output
  8. # -h | --help This text
  9. # -n | --dry-run Do not execute
  10. # -r | --remove Remove link/file if it exists
  11. #
  12. # Examples:
  13. #
  14. # $ link2 -v /etc/passwd
  15. # ln -s /etc/passwd /home/george/bin/passwd
  16. #
  17. # $ link2 -v /etc/issue passwd
  18. # mv passwd passwd.20150609:052604EDT
  19. # ln -s /etc/issue passwd
  20. #
  21. # $ link2 -r -v /etc/issue passwd
  22. # link2: passwd already points to /etc/issue
  23. #
  24. # $ link2 -r -v /etc/issue passwd
  25. # rm -f passwd
  26. # ln -s /etc/issue passwd
  27. #
  28. # $ link2 -v /etc/passwd $HOME
  29. # ln -s /etc/passwd /home/george/passwd
  30. #
  31. #
  32. # Author:
  33. # George Jones
  34. set -e -u
  35. PROG_NAME=$0
  36. PROG_NAME=`basename $0`
  37. SHORT_OPTS='vdhnrs:'
  38. LONG_OPTS='verbose,debug,dry-run,help,remove,stack-size:'
  39. OPTS=`getopt -o $SHORT_OPTS --long $LONG_OPTS -n 'parse-options' -- "$@"`
  40. function usage() {
  41. cat <<END >&2
  42. usage: $PROG_NAME [options] target [link]
  43. -v | --verbose Echo command names
  44. -d | --debug Additional debugging output
  45. -h | --help This text
  46. -n | --dry-run Do not execute
  47. -r | --remove Remove link/file if it exists
  48. END
  49. exit 1
  50. }
  51. if [ $? != 0 ] ; then echo "Failed parsing options." >&2 ; exit 1 ; fi
  52. eval set -- "$OPTS"
  53. # Default values
  54. VERBOSE=false
  55. HELP=false
  56. DRY_RUN=false
  57. STACK_SIZE=0
  58. DEBUG=false
  59. REMOVE=false
  60. # Set user selected options
  61. while true; do
  62. case "$1" in
  63. -v | --verbose ) VERBOSE=true; shift ;;
  64. -d | --debug ) DEBUG=true; shift ;;
  65. -h | --help ) HELP=true; shift ;;
  66. -n | --dry-run ) DRY_RUN=true; shift ;;
  67. -r | --remove ) REMOVE=true; shift ;;
  68. -s | --stack-size ) STACK_SIZE="$2"; shift; shift ;;
  69. -- ) shift; break ;;
  70. * ) break ;;
  71. esac
  72. done
  73. if $DEBUG; then
  74. VERBOSE=true
  75. fi
  76. if $DEBUG; then
  77. echo VERBOSE=$VERBOSE
  78. echo DEBUG=$DEBUG
  79. echo HELP=$HELP
  80. echo DRY_RUN=$DRY_RUN
  81. echo REMOVE=$REMOVE
  82. echo STACK_SIZE=$STACK_SIZE
  83. fi
  84. # validate arguments
  85. if [[ "$STACK_SIZE" =~ '"^[0-9]+$' ]]; then
  86. echo "$PROG_NAME: stack_size must be an integer. Got /$STACK_SIZE/" >&2
  87. usage
  88. fi
  89. # get file arguments
  90. if [ "$#" -lt 1 ]; then
  91. echo $PROG_NAME: Missing target
  92. usage
  93. fi
  94. if $HELP; then
  95. usage
  96. fi
  97. file=$1
  98. whereto=${2:-"${PWD}"}
  99. # figure out the link target, make sure it exists
  100. target="`readlink -f $file`"
  101. if $DEBUG; then echo target $target; fi
  102. if [ ! -e ${target} ]; then
  103. echo $0: ${target} does not exist >&2
  104. exit 1
  105. fi
  106. # figure out the link source, using basename of target
  107. base=`basename $file`
  108. if [ -d `readlink -f "${whereto}"` ]; then
  109. link="${whereto}""/""${base}"
  110. else
  111. link=${whereto}
  112. fi
  113. # Remove link if it exists
  114. if $REMOVE && [ -h $link -o -f $link ]; then
  115. if $DRY_RUN || $VERBOSE; then
  116. echo rm -f $link
  117. fi
  118. if ! $DRY_RUN; then
  119. rm -f $link
  120. fi
  121. fi
  122. # move any pre-existing file to a dated save version, unless it's the same
  123. now=`date "+%Y%m%d:%H%M%S%Z"`
  124. if [ -e ${link} ]; then
  125. # TODO abort here if target already points to target.
  126. expandedLink=`readlink -e ${link}`
  127. expandedTarget=`readlink -e ${target}`
  128. if [ ${expandedLink} == ${expandedTarget} ]; then
  129. echo $PROG_NAME: ${link} already points to ${target} >&2
  130. exit 0
  131. fi
  132. if $DRY_RUN || $VERBOSE; then
  133. echo mv ${link} "${link}.${now}"
  134. fi
  135. if ! $DRY_RUN; then
  136. mv ${link} "${link}.${now}"
  137. fi
  138. fi
  139. # finally, make the link
  140. if $DEBUG; then echo target $target >&2; fi
  141. if $DRY_RUN || $VERBOSE; then
  142. echo ln -s ${target} ${link}
  143. fi
  144. if ! $DRY_RUN; then
  145. ln -s ${target} ${link}
  146. fi