I'm trying to create a script to swap the location of a symbolic link in the current directory and the target file in another (relative) directory. Unfortunately, I can't figure out how to make the link in the non-local directory and searches for info on 'ln -s' only retrieve simple case uses. I realize I could 'cd' to the other directory within my script, but I figure there must be a more 'elegant' way.

Here's what I have

# Script to help organize repositories.
# Finds local links and swaps them with their target.
# Expects 1 arguments

if [ "$#" -ne 1 ];
    echo "Error in $0:  Need 1 arguments: <SYMBOLICLINK>";
    exit 1;

LINKBASE="$(basename "$LINK")";
LINKDIR="$(dirname "$LINK")";

TARGET="$(readlink "$LINK")";
TARGETBASE="$(basename "$TARGET")";
TARGETDIR="$(dirname "$TARGET")";

echo "Link:   $LINK";
echo "Target: $TARGET";

#Test for broken link
# test if symlink is broken (by seeing if it links to an existing file)
if [ -h "$LINK" -a ! -e "$LINK"  ] ; then
    echo "Symlink $LINK is broken.";
    echo "Exiting\n";
    exit 1;

mv -f "$TARGET" "/tmp/.";
#   printf "$TARGET copied to /tmp/\n" || exit 1;
mv -f "$LINK" "/tmp/$LINKBASEBKUP";# &&
#   printf "$LINKBASE copied to /tmp/$LINKBASEBKUP\n"; # ||

#   { printf "Exiting"; exit 1; }
# and alternative way to check errors
# [ $? -neq 0 ] && printf "Copy $LINK to $REFDIRNEW failed\nExiting"

mv "/tmp/$TARGETBASE" "$LINK";  #what was a link is now a file (target)
ln -s "$LINK" "$TARGET"; #link is target and target is link

if [ $? -eq 0 ];
    echo "Success!";
    exit 0
    echo "Couldn't make link to new target. Restoring link and target and exiting";
    mv "/tmp/$LINKBASEBKUP" "$LINK";
    mv "/tmp/$TARGETBASE" "$TARGET";
    exit 1;

Any help woudl be appreciated.

  • According to unix.stackexchange.com/a/149437/114944 I need to use the full path instead of "$LINK", but I'd like to avoid using the absolute path and, instead use the relative path. – mikemtnbikes Jan 14 at 20:57
  • 1
    i don't understand your question but simple cp -a and unlink will move relative symlink to another dir – alecxs Jan 14 at 22:33

Assuming you're using GNU tools, you could determine the absolute paths to link and target and use ln -r or use realpath's --relative-to option to create relative link targets.

Here's a minimal example without sanity checks or cleanup of the link backup:


link=$(realpath -s "$1")  # absolute path to link
target=$(realpath "$1")   # absolute path to target

mv -vf "$link"{,.bak}     # create link backup
mv -vf "$target" "$link"  # move target

# a) use ln -r
ln -vsr "$link" "$target"

# b) or determine the relative path
#target_dir=$(dirname "$target")
#relpath=$(realpath --relative-to="$target_dir" "$link")
#ln -vs "$relpath" "$target"
  • Thanks, I was unaware of the -r option or realpath. – mikemtnbikes Jan 15 at 19:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.