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. Commented Jan 14, 2021 at 20:57
  • 1
    i don't understand your question but simple cp -a and unlink will move relative symlink to another dir
    – alecxs
    Commented Jan 14, 2021 at 22:33

1 Answer 1


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. Commented Jan 15, 2021 at 19:49

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .