преобразовать мягкие ссылки в жесткие с помощью cp

преобразовать мягкие ссылки в жесткие с помощью cp

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 в этом примере) не является абсолютным. Но общая идея должна быть хорошей.

Связанный контент