cp
На странице команды доступны следующие info
опции :--preserve=
links
Сохраните в конечных файлах любые ссылки между соответствующими исходными файлами. Обратите внимание, чтос-L' or
-H', эта опцияможетпреобразовать символические ссылки в жесткие ссылки.
а затем пример, который я [сейчас] не понимаю; в любом случае:
Вопрос: Как превратить soft- в hardlinks с помощью cp
? И есть ли обратный путь [преобразование hard- в softlinks]?
Вторичный выпуск: Где жеможетв приведенной выше цитате вступают в игру? Я понимаю цель -L
и -H
, я могу копировать полностью функциональные мягкие ссылки и т. д., но пока мне не удалось превратить мягкие ссылки в жесткие.
решение1
Пример на информационной странице показывает, как это сделать, хотя этот пример немного сложен для понимания:
$ mkdir c; : > a; ln -s a b; cp -aH a b c; ls -i1 c
74161745 a
74161745 b
Давайте разберем это на составляющие команды:
mkdir c;
: создает каталогc/
: > a;
: просто быстрый способ создания пустого файла. Он эквивалентенecho "" > a
.:
— встроенный bash, который ничего не делает, смhelp :
. .ln -s a b
: создать мягкую ссылку наa
названныйb
. На данный момент это содержимое текущего каталога:$ ls -l | cc2ter total 4 -rw-r--r-- 1 terdon terdon 0 Oct 9 02:50 a lrwxrwxrwx 1 terdon terdon 1 Oct 9 02:50 b -> a drwxr-xr-x 2 terdon terdon 4096 Oct 9 02:50 c
Обратите внимание, что
b
это символическая ссылка (мягкая ссылка), она не указывает на тот же индексный дескриптор, что иa
:$ ls -i1c a b 16647344 a 16647362 b
cp -aH a b c;
: копировать файлыa
иb
в каталогc
. Здесь происходит преобразование, передаются следующие параметрыcp
:-a, --archive same as -dR --preserve=all -d same as --no-dereference --preserve=links -H follow command-line symbolic links in SOURCE
Необходимо
-H
, потому что (изinfo cp
):При копировании из символической ссылки `cp' обычно следует по ссылке только в том случае, если копирование не выполняется рекурсивно.
Так как
-a
активирует рекурсивное копирование (-R
),-H
необходимо следовать символическим ссылкам.-H
означает, что ссылки следуют несмотря на рекурсию и приведут к созданию жестких ссылок в целевом каталоге. Это содержимоеc/
после последнего шага (первый столбец — номер инода):$ ls -li c total 0 17044704 -rw-r--r-- 2 terdon terdon 0 Oct 9 02:50 a 17044704 -rw-r--r-- 2 terdon terdon 0 Oct 9 02:50 b
Теперь о том, как именно это работает, насколько я могу понять, поэкспериментировав с ним, cp --preserve=links
в сочетании с -L
или -H
преобразует символические ссылки в жесткие ссылки, еслии ссылка, и цель копируются втакой жекаталог.
На самом деле, как утверждает ОПвыяснил, по крайней мере в системах Debian, cp --preserve=links
достаточно для преобразования символических ссылок в жесткие ссылки, если целевой каталог тот же.
решение2
Я отправил отчет о возможной ошибке в команду coreutils @gnu.org в info cp
документации и получил следующий ответ:
Документация здесь немного кратка. Основная проблема в том, что -a подразумевает -d, а это подразумевает --no-dereference, который требуется для того, чтобы ваши команды работали так, как ожидается. IE --no-dereference требуется, чтобы остановить cp, неявно следуя символическим ссылкам в источнике.
Для проверки и разбиения демонстрируемой здесь детали:
$ mkdir links; : > a; ln -s a b;
Здесь мы видим, что -d переопределяет -H, который идет после. Поэтому мы не будем разыменовывать символические ссылки в первую очередь.
$ rm links/*; cp -H -d a b links $ l links/ lrwxrwxrwx. 1 padraig 1 Oct 10 09:37 b ▪▶ a -rw-rw-r--. 1 padraig 0 Oct 10 09:37 a
Здесь мы видим, что -H теперь учитывается, поскольку он идет последним, и поэтому символические ссылки следуют в источнике, что приводит к появлению жестких ссылок в месте назначения.
$ rm links/* $ rm links/*; cp -d -H a b links $ l links -rw-rw-r--. 2 padraig 0 Oct 10 09:37 b -rw-rw-r--. 2 padraig 0 Oct 10 09:37 a
Я сделаю документы более подробными, добавив следующее:
diff --git a/doc/coreutils.texi b/doc/coreutils.texi index b273627..aeed4ca 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -8257,9 +8257,11 @@ $ mkdir c; : > a; ln -s a b; cp -aH a b c; ls -i1 c @noindent
Обратите внимание на входные данные:
@file{b}
это символическая ссылка на обычный файл@file{a}
, однако файлы в целевом каталоге@file{c/}
являются жестко связанными.
- Поскольку
@option{-a}
подразумевает@option{--preserve=links}
, а поскольку@option{-H}
указывает@command{cp}
на необходимость разыменования аргументов командной строки, он видит два файла с одинаковым номером inode и сохраняет воспринимаемую жесткую ссылку.- Поскольку
@option{-a}
подразумевает,@option{--no-dereference}
что он скопирует символическую ссылку, но позже@option{-H}
сообщает@command{cp}
о необходимости разыменовать аргументы командной строки, где он затем видит два файла с одинаковым номером inode. Тогда опция,@option{--preserve=links}
также подразумеваемая,@option{-a}
сохранит воспринимаемую жесткую ссылку.
решение3
Было бы сложно преобразовать жесткие ссылки в символические. В случае жесткой ссылки есть блок данных в файловой системе, на который указывают две или более записей файлов. Нет никаких «источников» и «мест назначения»; это буквально один файл с несколькими эквивалентными именами. Вы можете использовать GNU find, чтобы идентифицировать их следующим образом:
sauer@zipper:~$ find . -type f -links +1 -printf "%i: %p (%n)\n"
609: ./link1 (2)
609: ./link2 (2)
Как только у вас будут все файлы с одинаковым inode, вам придется выбрать один, чтобы он был "настоящим" файлом, а затем просто заменить все остальные символическими ссылками на главный файл. Вероятно, это можно сделать так:
sauer@zipper:~$ find . -type f -links +1 -printf "%i %p\n" | sort -nk1
609 ./link1
609 ./link2
А затем скрипт должен выяснить, как выбрать одно из значений с тем же номером, чтобы все остальные ссылались на него. Возможно, первое значение станет целью, а все остальные с тем же inode будут ссылаться на него. Вот один действительно простой, непроверенный пример скрипта оболочки
#!/bin/sh
prev=""
target=""
find /tmp -type f -links +1 -printf "%i %p\n" | sort -nk1 \
| while read inode file
do
if [[ $inode != $prev ]]
then
target="$file"
prev=$inode
else
ln -sf "$target" "$file"
fi
done
Существуют потенциальные проблемы, в том, что ссылки из разных каталогов могут быть созданы с недопустимой целью, если путь в find (/tmp в этом примере) не является абсолютным. Но общая идея должна быть хорошей.