移动文件并用符号链接替换它

移动文件并用符号链接替换它

有人可以给我一个命令:

  • 将文件移动到新目录
  • 并在旧位置留下一个指向新位置的符号链接

答案1

mv移动文件并ln -s创建符号链接,因此基本任务是通过执行这两个命令的脚本完成的:

#!/bin/sh
mv -- "$1" "$2"
ln -s -- "$2" "$1"

有一些注意事项。如果第二个参数是目录,mv则会将文件移动到该目录中,但ln -s会创建指向该目录而不是移动的文件的链接。

#!/bin/sh
set -e
original="$1" target="$2"
if [ -d "$target" ]; then
  target="$target/${original##*/}"
fi
mv -- "$original" "$target"
ln -s -- "$target" "$original"

另一个需要注意的是,第一个参数ln -s是符号链接的确切文本。它与目标的位置相关,而不是与执行命令的目录相关。如果原始位置不在当前目录并且目标不是用绝对路径表示,则链接将不正确。在这种情况下,需要重写路径。在这种情况下,我将创建一个绝对链接(相对链接更好,但更难正确)。此脚本假定您没有以换行符结尾的文件名。

#!/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"

如果您有多个文件,请循环处理它们。

#!/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

答案2

我通常使用这个单行函数:

function ml() { mkdir -p "$(dirname "$1")" && rsync -aP --no-links "$1" "$2" && ln -sf "$2" "$1" }

用法与 m​​v 或 cp 类似:

ml old_file target_dir/new_file_name

分解一下:

  • mkdir -p "$(dirname "$1")"- 如果目标目录尚不存在,则创建它
    • dirname "$1"- 获取路径的目录部分(去掉文件名)
  • rsync -aP --no-links "$1" "$2"- 将文件复制到目的地。mv "$1" "$2"如果两个文件位于同一文件系统上, 请将其替换为以获得更好的性能。
    • -a- 保留所有权和所有其他权限。您可以调整它以仅保留您想要的组件。
    • -P- 显示进展。
    • --no-links- 不要复制链接——这意味着您可以在同一个文件上多次运行此命令,并且您永远不会因为意外地用自身的符号链接覆盖目标文件而丢失文件。
  • ln -sf "$2" "$1"- 使用新文件的符号链接覆盖旧文件
    • -s- 使用符号链接
    • -f- 覆盖旧文件

答案3

将其放入 .sh 文件并使其可执行(chmod +x filename):

#!/bin/bash

mv "$1" "$2"
ln -s "$2" "$1"

使用示例:

./test.sh asdf otherdir/asdf

请注意,这不会进行安全检查等。根据您的任务的复杂程度,这可能就足够了。

相关内容