Как преобразовать ссылку в обычный файл?

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

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

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

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

14 ответов


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

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

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


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

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

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


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

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

вобще-рядный sed без преобразования:

sed -i ';' /path/to/symbolic/link

на OSX

rsync `readlink bar.pdf ' bar.формат PDF


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

$ mv target link

если мы не знаем цель, мы заменим выражение $(readlink link) на target выше:

$ mv $(readlink link) link

на mv утилиты соответствует rename системный вызов в POSIX-подобных системах (по крайней мере, когда они не работают на разных томах файловой системы). The 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

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

cp --remove-destination target filename

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

cp --remove-destination `readlink file` file

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

добавлять рекурсивные и силу не работает:

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

cp: не удается скопировать каталог "путь / файл" в себя, "файл"

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

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

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


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

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

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


нет единой команды. Но если вам не нужна копия, и все, что вам нужно, это еще одна ссылка, вы можете заменить символическую ссылку ссылкой (она же "жесткая ссылка"). Это работает, только если они находятся в одном разделе, кстати.

rm filename
ln target filename

Rsync может nativly уважать символическую ссылку для вас, используя флаг-L.

[user@workstation ~]$ rsync -h | grep -- -L
 -L, --copy-links            transform symlink into referent file/dir

это будет так: rsync -L <symlink> <destination>


в случае" относительных " символических ссылок вы можете добавить оператор awk в @jared answer:

for f in $(find . -type l); do /bin/cp -rf --remove-destination -f $(find . \! -type l -name $(readlink $f | awk -F"../" '{print $NF}')) $f;done;

Если у вас есть символические ссылки, указывающие на каталоги, вам нужно использовать более радикальный подход, потому что cp --remove-destination не работает вместе с каталогами символических ссылок правильно

for f in `find . -type l`; do (cd `dirname $f`; target=`basename $f`; source=`readlink $target` ; rm -rf $target && cp -r $source $target); done

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


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

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

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

rsync --archive --copy-links --recursive folderContainingSymlinkFilesAndSymlinkfoldersandsubfolders myNewFolder


другой подход, если вы часто делаете это, - это адаптация ответа kbrock в сценарий оболочки и его размещение в /usr/bin/. Что-то вроде:

if [ $# -ne 1 ] 
then
  echo "Usage:  filename"
  exit 1
fi
[ -L "" ] && cp --remove-destination "$(readlink "")" ""

chmod +x, а затем просто запустите его как обычную команду.