Move a file and replace it by a symlink
mv
moves a file, and ln -s
creates a symbolic link, so the basic task is accomplished by a script that executes these two commands:
#!/bin/sh
mv -- "$1" "$2"
ln -s -- "$2" "$1"
There are a few caveats. If the second argument is a directory, then mv
would move the file into that directory, but ln -s
would create a link to the directory rather than to the moved file.
#!/bin/sh
set -e
original="$1" target="$2"
if [ -d "$target" ]; then
target="$target/${original##*/}"
fi
mv -- "$original" "$target"
ln -s -- "$target" "$original"
Another caveat is that the first argument to ln -s
is the exact text of the symbolic link. It's relative to the location of the target, not to the directory where the command is executed. If the original location is not in the current directory and the target is not expressed by an absolute path, the link will be incorrect. In this case, the path needs to be rewritten. In this case, I'll create an absolute link (a relative link would be preferable, but it's harder to get right). This script assumes that you don't have file names that end in a newline character.
#!/bin/sh
set -e
original="$1" target="$2"
if [ -d "$target" ]; then
target="$target/${original##*/}"
fi
mv -- "$original" "$target"
case "$original" in
*/*)
case "$target" in
/*) :;;
*) target="$(cd -- "$(dirname -- "$target")" && pwd)/${target##*/}"
esac
esac
ln -s -- "$target" "$original"
If you have multiple files, process them in a loop.
#!/bin/sh
while [ $# -gt 1 ]; do
eval "target=\${$#}"
original="$1"
if [ -d "$target" ]; then
target="$target/${original##*/}"
fi
mv -- "$original" "$target"
case "$original" in
*/*)
case "$target" in
/*) :;;
*) target="$(cd -- "$(dirname -- "$target")" && pwd)/${target##*/}"
esac
esac
ln -s -- "$target" "$original"
shift
done