Как преобразовать символическую ссылку в обычный файл?
Каков самый прямой способ преобразования символической ссылки в обычный файл (т.е. копия цели символической ссылки)?
Предположим, что filename
является символической ссылкой на target
. Очевидная процедура превращения его в копию:
cp filename filename-backup
rm filename
mv filename-backup filename
Есть ли более прямой способ (т.е. одна команда)?
Ответы
Ответ 1
Нет единой команды для преобразования символической ссылки в обычный файл. Самый прямой способ - использовать readlink
, чтобы найти файл, на который указывает символическая ссылка, а затем скопировать этот файл через символическую ссылку:
cp --remove-destination `readlink bar.pdf` bar.pdf
Конечно, если bar.pdf
является, на самом деле, обычным файлом для начала, тогда это скроет файл. Поэтому было бы целесообразно провести проверку правильности.
Ответ 2
Просто перефразируйте другие ответы, но добавив "проверку работоспособности", чтобы убедиться, что связанная ссылка на самом деле является символической ссылкой:
removelink() {
[ -L "$1" ] && cp --remove-destination "$(readlink "$1")" "$1"
}
Это говорит о том, что если файл является символической ссылкой, запустите команду копирования.
Ответ 3
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
Ответ 4
Для текстовых файлов команда sed
может сделать это в одной строке, если вы передадите ей переключатель на месте (-i
). Это связано с тем, что sed
выполняет одиночный проход по файлу, выдает котировку во временный файл, который впоследствии переименовывает в соответствии с оригиналом.
Просто выполните встроенный sed
без преобразований:
sed -i ';' /path/to/symbolic/link
Ответ 5
В OSX
rsync `readlink bar.pdf` bar.pdf
Ответ 6
Нет необходимости в каких-либо смешных сценариях оболочки, 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
Ответ 7
cp может удалить целевой файл:
cp --remove-destination target filename
Ответ 8
Многие уже заявили следующее решение:
cp --remove-destination `readlink file` file
Однако это не будет работать с символически связанными каталогами.
Добавление рекурсивной и силы не будет работать:
cp -rf --remove-destination `readlink file` file
cp: невозможно скопировать каталог, путь/файл в себя, файл
Поэтому, вероятно, более безопасно сначала удалить символическую ссылку:
resolve-symbolic-link() {
if [ -L $1 ]; then
temp="$(readlink "$1")";
rm -rf "$1";
cp -rf "$temp" "$1";
fi
}
Не совсем один лайнер, как вы надеялись, но поместите его в оболочку, и это может быть.
Ответ 9
Это отлично сработало для меня (отредактировано для работы с пробелами):
find . -type l | while read f; do /bin/cp -rf --remove-destination -f $(find . -name $(readlink "${f}")) "${f}";done;
Позволяет рекурсивно преобразовывать все символические ссылки под текущей рабочей папкой в свой обычный файл. Также не просит вас перезаписать. "/bin/cp" существует, чтобы вы могли обойти возможный псевдоним cp -i на вашей ОС, который предотвращает работу "-rf".
Ответ 10
Нет единой команды. Но если вам не нужна копия, и все, что вам нужно, это еще одна ссылка, вы можете заменить символическую ссылку ссылкой (иначе говоря, "жесткой ссылкой" ). Это работает только в том случае, если они находятся в одном разделе, BTW.
rm filename
ln target filename
Ответ 11
Rsync может нейтрально использовать символическую ссылку для вас, используя флаг -L.
[[email protected] ~]$ rsync -h | grep -- -L
-L, --copy-links transform symlink into referent file/dir
Было бы просто: rsync -L <symlink> <destination>
Ответ 12
в случае "относительных" символических ссылок вы можете добавить оператор awk в ответ @jared:
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
Конечно, это может быть написано с меньшими затратами. но, на мой взгляд, неплохо читать.
Ответ 13
Это решение работает с файлами symlink и папками/подпапками symlink.
Требуется одна строка, не требуется script.
Это было бы идеально для экспорта или передачи символических ссылок в другом месте.
Поместите все в папку.
rsync --archive --copy-links --recursive folderContainingSymlinkFilesAndSymlinkFoldersAndSubfolders myNewFolder
Ответ 14
Другой подход, если вы часто это делаете, - это адаптировать ответ kbrock в оболочку script и поместить его в /usr/bin/. Что-то вроде:
if [ $# -ne 1 ]
then
echo "Usage: $0 filename"
exit 1
fi
[ -L "$1" ] && cp --remove-destination "$(readlink "$1")" "$1"
chmod + x it, а затем просто запустите его как обычную команду.