1

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

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

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

LINK="$1"; LINKBASE="$(basename "$LINK")"; LINKDIR="$(dirname "$LINK")"; LINKBASEBKUP="$LINK-bkup";

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; fi

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 ]; then echo "Success!"; exit 0 else echo "Couldn't make link to new target. Restoring link and target and exiting"; mv "/tmp/$LINKBASEBKUP" "$LINK"; mv "/tmp/$TARGETBASE" "$TARGET"; exit 1; fi

Any help woudl be appreciated.

  • According to https://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 '21 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 '21 at 22:33

1 Answers1

2

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:

#!/bin/bash

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"

Freddy
  • 25,565