Softlinks in Hardlinks umwandeln mit cp

Softlinks in Hardlinks umwandeln mit cp

Die cpBefehlsseite infobietet 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 -Lund -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 mit echo "" > a. :ist eine in Bash integrierte Funktion, die nichts tut, siehe help :.
  • ln -s a b: Erstellen Sie einen Softlink mit adem Namen b. 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 bsich um einen symbolischen Link (Softlink) handelt. Er verweist nicht auf denselben Inode wie a:

    $ ls -i1c a b
    16647344 a
    16647362 b
    
  • cp -aH a b c;: Dateien in das Verzeichnis kopieren a. bHier cfindet die Konvertierung statt. Die übergebenen Optionen cpsind:

    -a, --archive
          same as -dR --preserve=all
    -d    same as --no-dereference --preserve=links
    -H    follow command-line symbolic links in SOURCE
    

    Das -Hist notwendig, weil (von info cp):

    Beim Kopieren von einem symbolischen Link folgt „cp“ dem Link normalerweise nur, wenn nicht rekursiv kopiert wird.

    Da -arekursives Kopieren aktiviert wird ( -R), -Hist es notwendig, symbolischen Links zu folgen. -Hbedeutet, dass Links trotz Rekursion verfolgt werden und Hardlinks im Zielverzeichnis erstellt werden. Dies sind die Inhalte von c/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=linksKombination mit symbolischen Links -Loder -Hin Hardlinks umwandeln, wennSowohl der Link als auch das Ziel werden in dieDasselbeVerzeichnis.


Tatsächlich, wie das OPherausgefundenreicht zumindest auf Debian-Systemen aus, cp --preserve=linksum Symlinks in Hardlinks umzuwandeln, wenn das Zielverzeichnis dasselbe ist.

Antwort2

Ich habe einen Bericht über einen möglichen Fehler in der info cpDokumentation 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.

verwandte Informationen