Как преобразовать ссылку в обычный файл?
каков наиболее прямой способ преобразования символической ссылки в обычный файл (т. е. копию цели символической ссылки)?
предположим 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
нет необходимости в каких-либо забавных скриптов, 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 --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, а затем просто запустите его как обычную команду.