Die cp
Befehlsseite info
bietet zu dieser Option --preserve=
Folgendes:
links
Behalten Sie in den Zieldateien alle Links zwischen entsprechenden Quelldateien bei. Beachten Sie, dassmit-L' or
-H', diese Optiondürfensymbolische Links in Hardlinks umwandeln.
gefolgt von einem Beispiel, das ich [jetzt] nicht verstehe; jedenfalls:
Frage: Wie kann man mit Soft- in Hardlinks umwandeln cp
? Und gibt es auch einen Weg zurück [von Hard- in Softlinks]?
Sekundäres Problem: Wodürfenim obigen Zitat ins Spiel? Ich verstehe den Zweck von -L
und -H
, ich kann voll funktionsfähige Softlinks usw. kopieren, aber bisher habe ich es nicht geschafft, Soft- in Hardlinks umzuwandeln.
Antwort1
Das Beispiel auf der Infoseite zeigt, wie das geht, ist allerdings etwas schwer zu verstehen:
$ mkdir c; : > a; ln -s a b; cp -aH a b c; ls -i1 c
74161745 a
74161745 b
Lassen Sie uns das in die einzelnen Befehle aufschlüsseln:
mkdir c;
: erstellt das Verzeichnisc/
: > a;
: nur eine schnelle Möglichkeit, eine leere Datei zu erstellen. Es ist gleichwertig mitecho "" > a
.:
ist eine in Bash integrierte Funktion, die nichts tut, siehehelp :
.ln -s a b
: Erstellen Sie einen Softlink mita
dem Namenb
. An dieser Stelle sind dies die Inhalte des aktuellen Verzeichnisses:$ 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
Beachten Sie, dass es
b
sich um einen symbolischen Link (Softlink) handelt. Er verweist nicht auf denselben Inode wiea
:$ ls -i1c a b 16647344 a 16647362 b
cp -aH a b c;
: Dateien in das Verzeichnis kopierena
.b
Hierc
findet die Konvertierung statt. Die übergebenen Optionencp
sind:-a, --archive same as -dR --preserve=all -d same as --no-dereference --preserve=links -H follow command-line symbolic links in SOURCE
Das
-H
ist notwendig, weil (voninfo cp
):Beim Kopieren von einem symbolischen Link folgt „cp“ dem Link normalerweise nur, wenn nicht rekursiv kopiert wird.
Da
-a
rekursives Kopieren aktiviert wird (-R
),-H
ist es notwendig, symbolischen Links zu folgen.-H
bedeutet, dass Links trotz Rekursion verfolgt werden und Hardlinks im Zielverzeichnis erstellt werden. Dies sind die Inhalte vonc/
nach dem letzten Schritt (die erste Spalte ist die Inode-Nummer):$ 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
Wie das genau funktioniert, kann ich, soweit ich es durch Herumspielen herausfinden kann, in cp --preserve=links
Kombination mit symbolischen Links -L
oder -H
in Hardlinks umwandeln, wennSowohl der Link als auch das Ziel werden in dieDasselbeVerzeichnis.
Tatsächlich, wie das OPherausgefundenreicht zumindest auf Debian-Systemen aus, cp --preserve=links
um Symlinks in Hardlinks umzuwandeln, wenn das Zielverzeichnis dasselbe ist.
Antwort2
Ich habe einen Bericht über einen möglichen Fehler in der info cp
Dokumentation an das Coreutils-Team @gnu.org gesendet und diese Antwort erhalten:
Die Dokumentation ist hier etwas knapp gehalten. Das Hauptproblem ist, dass -a -d impliziert und das wiederum --no-dereference impliziert, was erforderlich ist, damit Ihre Befehle wie erwartet funktionieren. IE --no-dereference ist erforderlich, um zu verhindern, dass cp implizit symbolischen Links in der Quelle folgt.
So überprüfen und teilen Sie die hier gezeigten Details auf:
$ mkdir links; : > a; ln -s a b;
Hier sehen wir, dass -d -H überschreibt, da es danach kommt. Daher werden wir Symlinks gar nicht erst dereferenzieren.
$ 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
Hier sehen wir, dass -H jetzt berücksichtigt wird, da es zuletzt kommt, und daher werden symbolische Links in der Quelle befolgt, was zu Hardlinks im Ziel führt.
$ 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
Ich werde die Dokumentation wie folgt etwas deutlicher machen:
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
Beachten Sie die Eingaben:
@file{b}
ist ein symbolischer Link zu einer normalen Datei@file{a}
, die Dateien im Zielverzeichnis@file{c/}
sind jedoch fest verknüpft.
- Da
@option{-a}
impliziert@option{--preserve=links}
und anweist,@option{-H}
Befehlszeilenargumente@command{cp}
zu dereferenzieren, erkennt es zwei Dateien mit derselben Inode-Nummer und behält den wahrgenommenen Hardlink bei.- Da
@option{-a}
impliziert,@option{--no-dereference}
dass der Symlink kopiert wird, aber später@option{-H}
wird angewiesen@command{cp}
, die Befehlszeilenargumente zu dereferenzieren, wo dann zwei Dateien mit derselben Inode-Nummer angezeigt werden. Dann behält die@option{--preserve=links}
ebenfalls implizierte Option@option{-a}
den wahrgenommenen Hardlink bei.
Antwort3
Es wäre schwierig, Hardlinks in Symlinks umzuwandeln. Bei einem Hardlink gibt es einen Datenblock im Dateisystem, auf den zwei oder mehr Dateieinträge verweisen. Es gibt keine „Quelle“ und kein „Ziel“. Es handelt sich buchstäblich um eine Datei mit mehreren gleichwertigen Namen. Sie können GNU find verwenden, um diese auf diese Weise zu identifizieren:
sauer@zipper:~$ find . -type f -links +1 -printf "%i: %p (%n)\n"
609: ./link1 (2)
609: ./link2 (2)
Sobald Sie alle Dateien mit demselben Inode haben, müssen Sie eine als „echte“ Datei auswählen und dann alle anderen durch symbolische Links zur Masterdatei ersetzen. Dies lässt sich wahrscheinlich folgendermaßen bewerkstelligen:
sauer@zipper:~$ find . -type f -links +1 -printf "%i %p\n" | sort -nk1
609 ./link1
609 ./link2
Und dann muss ein Skript herausfinden, wie man einen der Werte mit der gleichen Nummer auswählt, damit alle anderen darauf verweisen. Vielleicht wird der erste zum Ziel und alle weiteren mit dem gleichen Inode werden symbolisch darauf verlinkt. Hier ist ein wirklich einfaches, ungetestetes Shell-Skriptbeispiel
#!/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
Es gibt potenzielle Probleme, da Links aus verschiedenen Verzeichnissen mit einem ungültigen Ziel erstellt werden können, wenn der Pfad in find (in diesem Beispiel /tmp) nicht absolut ist. Aber das Grundprinzip sollte in Ordnung sein.