Created
January 7, 2014 23:24
-
-
Save kurahaupo/8308796 to your computer and use it in GitHub Desktop.
Convert absolute symbolic links (those whose target starts with /) to be relative (to their containing directory). Written for Linux, but will work anywhere that has `readlink -m` and `ln -T` (the GNU versions do).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
dryrun=false | |
verbose=false | |
root=/ | |
[[ "--help" = "$1"* && $1 = --h* || "$*" = -h ]] && { cat <<EndOfHelp ; exit 0 ; } | |
${0##*/} [-v|-q] [-n|-N] [-r /PATH] [PATH ...] | |
EndOfHelp | |
while [[ $1 = -?* ]] | |
do | |
case $1 in | |
(-[r]?*) _p=$1 ; shift ; set -- "${_p:0:2}" "${_p:2}" "$@" ; continue ;; | |
(-[^-]?*) _p=$1 ; shift ; set -- "${_p:0:2}" "-${_p:2}" "$@" ; continue ;; | |
(-N) dryrun=false ;; | |
(-n) dryrun=true ;; | |
(-q) verbose=false ;; | |
(-r) root=$2 ; shift ;; | |
(-v) verbose=true ;; | |
(*) echo >&2 "Invalid option '$1'" ; exit 64 ;; | |
esac | |
shift | |
done | |
for l do | |
# canonicalize path (without resolving symlinks) | |
[[ $l = /* ]] || l=${PWD%/}/$l | |
l=${l//\/\//\/} | |
while [[ $l = */./* ]] ; do l=${l//\/.\//\/} ; done | |
t=$(readlink $l) || continue # must be a symlink | |
# canonicalize path AND resolve symlinks | |
u=$(readlink -m $l) || break # something very broken | |
[[ $l = ${root%/}/* ]] || continue # symlink out of balliwick | |
[[ $u = ${root%/}/* ]] || continue # target out of balliwick | |
# trim common prefix from both paths | |
# (or the entire target if it is a prefix of the symlink) | |
if [[ "$l" = "$u"/* ]] | |
then | |
v=${l#"$u"/} u=. | |
else | |
v=$l | |
while [[ "$u" = */* && "${u%%/*}" = "${v%%/*}" ]] | |
do u=${u#*/} v=${v#*/} | |
done | |
fi | |
# make target relative to symlink | |
w=${v//[^\/]/} | |
u=${w//\//..\/}$u | |
# do nothing if nothing to change | |
[[ "$t" = "$u" ]] && continue | |
if $verbose || $dryrun | |
then | |
printf "LINK %-47s REPLACE %-47s WITH %s\n" "$l" "$t" "$u" | |
fi | |
# | |
if $dryrun | |
then | |
echo "ln -sfTv '$u' '$l'" | |
echo "chown -hc --ref='$l~' '$l'" | |
echo "rm -fv '$l~'" | |
else | |
ln -sfTv --backup=simple "$u" "$l" && | |
chown -hc --ref="$l~" "$l" | |
[[ "$l" -ef "$l~" ]] && | |
rm -fv "$l~" | |
fi | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
wtf is it that long