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