Переместить файл и заменить его символической ссылкой

16

Может ли кто-нибудь дать мне команду, которая бы:

  • переместить файл в новый каталог
  • и оставьте символическую ссылку в ее старом местоположении к ее новой
Йо Б.
источник

Ответы:

19

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
Жиль "ТАК - перестань быть злым"
источник
1
Спасибо, Жиль, за сценарий и объяснения. Я постараюсь это понять!
Йо Б.
Это должно быть помечено как правильный ответ
Шридхар Сарнобат
Чтобы сделать этот ответ еще более удивительным, он rsync --remove-source-filesможет быть более информативным для пользователей, которые переносят большой файл с диска, что может занять некоторое время.
Шридхар Сарнобат
Я думаю, что вы должны вызывать sh с -e, чтобы это приводило к ошибкам, например, если вы остановите команду mv, потому что файл уже существует
Alex
2

Поместите это в файл .sh и сделайте его исполняемым ( chmod +x filename):

#!/bin/bash

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

Пример использования:

./test.sh asdf otherdir/asdf

Обратите внимание, что это не проверяет безопасность и т. Д. В зависимости от сложности вашей задачи, этого может быть достаточно.

MatthewRock
источник
Спасибо Мэтью, это прекрасно работает, когда применяется к одному файлу. Но вы можете мне помочь обобщая это двух каталогов , как это: ./test.sh .mozila/firefox/zotero/*/*.pdf MyBbliography/*.pdf. *Не кажется, работает с вашим test.sh. У вас есть обходной путь? Thx
Yo B.
2
@kadok Сценарий MatthewRock работает только для одного файла, и целью должен быть абсолютный путь, иначе источник должен находиться в текущем каталоге.
Жиль "ТАК - перестань быть злым"
Кроме того, он не будет работать, если $ 1 - это файл, а $ 2 - это каталог.
Шридхар Сарнобат
0

Я обычно использую эту однострочную функцию:

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

Использование похоже на mv или 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 - перезаписать старый файл
user60561
источник