Как преобразовать символическую ссылку в обычный файл? - PullRequest
49 голосов
/ 04 декабря 2011

Какой самый прямой способ преобразовать символическую ссылку в обычный файл (т. Е. Копию цели символической ссылки)?

Предположим, filename является символической ссылкой на target.Очевидная процедура для превращения его в копию:

cp filename filename-backup
rm filename
mv filename-backup filename

Есть ли более прямой путь (т. Е. Одна команда)?

Ответы [ 14 ]

48 голосов
/ 15 ноября 2012

Нет единой команды для преобразования символической ссылки в обычный файл.Самый прямой способ - использовать readlink, чтобы найти файл, на который указывает символическая ссылка, а затем скопировать этот файл по символической ссылке:

cp --remove-destination `readlink bar.pdf` bar.pdf

Конечно, если bar.pdf на самом делеобычный файл для начала, тогда это приведет к засорению файла.Поэтому рекомендуется провести некоторую проверку вменяемости.

21 голосов
/ 07 марта 2013

Просто перефразирую ответы других, но добавление «проверки работоспособности», чтобы убедиться, что переданная ссылка на самом деле является символической ссылкой:

removelink() {
  [ -L "$1" ] && cp --remove-destination "$(readlink "$1")" "$1"
}

Это говорит о том, что если файл является символической ссылкой, то выполните команду копирования.

17 голосов
/ 10 октября 2014
for f in $(find -type l);do cp --remove-destination $(readlink $f) $f;done;
  • Проверить символические ссылки в текущем каталоге и подкаталогах find -type l
  • Получить путь к связанному файлу readlink $f
  • Удалить символическую ссылку и скопировать файл cp --remove-destination $(readlink $f) $f
9 голосов
/ 08 сентября 2016

Нет необходимости в каких-либо забавных сценариях оболочки, rsync или специальных опциях GNU для cp. Все просто:

$ mv target link

Если мы не знаем цель, мы подставляем выражение $(readlink link) для target выше:

$ mv $(readlink link) link

Утилита mv соответствует системному вызову rename в POSIX-подобных системах (по крайней мере, когда она не работает на разных томах файловой системы). Системный вызов rename удаляет целевой объект, если он существует, за одну операцию.

Мы можем просто mv файл назначения на символическую ссылку:

$ touch target
$ ln -sf target link
$ ls -l target link
lrwxrwxrwx 1 kaz kaz 6 Sep  7  2016 link -> target
-rw-rw-r-- 1 kaz kaz 0 Sep  7  2016 target
$ mv target link
$ ls -l target link
ls: cannot access target: No such file or directory
-rw-rw-r-- 1 kaz kaz 0 Sep  7  2016 link

Если мы сделаем это для разных томов, это будет смоделировано. Сначала GNU Coreutils mv пытается выполнить системный вызов rename. Когда это не удается, он использует unlink для удаления целевой символической ссылки и выполняет копию:

$ touch /tmp/target
$ ln -sf /tmp/target link
$ ls -l /tmp/target link
lrwxrwxrwx 1 kaz kaz 11 Sep  7  2016 link -> /tmp/target
-rw-rw-r-- 1 kaz kaz  0 Sep  7 16:20 /tmp/target
$ strace mv /tmp/target link
[ ... snip ... ]
stat("link", {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
lstat("/tmp/target", {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
lstat("link", {st_mode=S_IFLNK|0777, st_size=11, ...}) = 0
rename("/tmp/target", "link")           = -1 EXDEV (Invalid cross-device link)
unlink("link")                          = 0
open("/tmp/target", O_RDONLY|O_NOFOLLOW) = 3
fstat(3, {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
open("link", O_WRONLY|O_CREAT|O_EXCL, 0600) = 4
fstat(4, {st_mode=S_IFREG|0600, st_size=0, ...}) = 0
fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
read(3, "", 65536)                      = 0
[ ... ]
close(0)                                = 0
close(1)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++
$ ls -l /tmp/target link
ls: cannot access /tmp/target: No such file or directory
-rw-rw-r-- 1 kaz kaz 0 Sep  7 16:20 link
9 голосов
/ 05 ноября 2015

Для текстовых файлов команда sed может сделать это в одну строку, если вы передадите ей переключатель на месте (-i).Это связано с тем, что sed делает один проход по файлу, выводит выходные данные во временный файл, который впоследствии переименовывается, чтобы соответствовать оригиналу.

Просто выполните inline sed без преобразований:

sed -i ';' /path/to/symbolic/link
7 голосов
/ 30 января 2013

В OSX

rsync `readlink bar.pdf` bar.pdf

4 голосов
/ 05 декабря 2011

cp может удалить файл назначения:

cp --remove-destination target filename
2 голосов
/ 18 мая 2015

Многие уже заявили следующее решение:

cp --remove-destination `readlink file` file

Однако это не будет работать на символически связанных каталогах.

Добавление рекурсивных и force также не будет работать:

cp -rf --remove-destination `readlink file` file

cp: невозможно скопировать каталог, 'path /file, сам по себе, 'file'

Поэтому, вероятно, безопаснее удалить символическую ссылку в первую очередь:

resolve-symbolic-link() {
  if [ -L $1 ]; then
      temp="$(readlink "$1")";
      rm -rf "$1";
      cp -rf "$temp" "$1";
  fi
}

Не совсем однострочный, как вы надеялись,но поместите это в свою оболочку, и это может быть.

1 голос
/ 09 июня 2016

Это решение работает с файлами символьных ссылок и папками / подпапками символических ссылок.

Одна строка, сценарий не требуется. Это было бы идеально для экспорта или передачи символических ссылок в другом месте.

Поместите все в папку.

rsync --архив --copy-ссылки - рекурсивная папкаКонтейнерSymlinkFilesAndSymlinkFoldersAndSubfolders myNewFolder

1 голос
/ 11 сентября 2015

Это прекрасно сработало для меня ( отредактировано для работы с пробелами ):

find . -type l | while read f; do /bin/cp -rf --remove-destination -f $(find . -name $(readlink "${f}")) "${f}";done;

Позволяет рекурсивно преобразовывать все символические ссылки в текущей рабочей папке в обычный файл. Также не просит вас перезаписать. «/ bin / cp» существует, так что вы можете обойти возможный псевдоним cp -i в вашей ОС, который не позволяет работать «-rf».

...