cp verhält sich komisch wenn. (Punkt) oder .. (Punkt Punkt) sind das Quellverzeichnis

15

Diese Antwort zeigt, dass man alle Dateien - auch versteckte - wie folgt von Verzeichnis srczu Verzeichnis kopieren kann dest:

mkdir dest
cp -r src/. dest

Es gibt keine Erklärung in der Antwort oder ihren Kommentaren, warum dies tatsächlich funktioniert, und niemand scheint Dokumentation dazu zu finden.

Ich habe ein paar Dinge ausprobiert. Zunächst der Normalfall:

$ mkdir src src/src_dir dest && touch src/src_file src/.dotfile dest/dest_file
$ cp -r src dest
$ ls -A dest
dest_file  src

Dann mit /.am Ende:

$ mkdir src src/src_dir dest && touch src/src_file src/.dotfile dest/dest_file
$ cp -r src/. dest
$ ls -A dest
dest_file  .dotfile  src_dir  src_file

Das verhält sich also ähnlich *, kopiert aber auch versteckte Dateien.

$ mkdir src src/src_dir dest && touch src/src_file src/.dotfile dest/dest_file
$ cp -r src/* dest
$ ls -A dest
dest_file  src_dir  src_file

.und ..sind richtige Hardlinks, wie hier erklärt , genau wie der Verzeichniseintrag selbst.

Woher kommt dieses Verhalten und wo ist es dokumentiert?

iFreilicht
quelle
3
Was meinst du damit, niemand kann Dokumentation finden? Die cpReferenz erklärt klar, wie es cp -Rfunktioniert. .und ..Verzeichnisse sind genau wie alle anderen Verzeichnisse, es gibt nichts Magisches oder Geheimnisvolles an ihnen.
AlexP
2
@AlexP Ich habe die Antwort bearbeitet, um sie klarer zu machen. Der springende Punkt ist , dass .und ..nicht wie andere Verzeichnisse verhalten.
iFreilicht
Ich habe versucht , zu erklären , warum es funktioniert , wie ein Ordner rekursiv in einer Idempotent Weise kopieren mit cp
roaima

Antworten:

27

Das Verhalten ist ein logisches Ergebnis des dokumentierten Algorithmus für cp -R. Siehe POSIX , Schritt 2f:

Die Dateien im Verzeichnis source_file werden in dem Verzeichnis kopiert werden dest_file , die vier Stufen (1 bis 4) aufgeführt hier mit den Dateien wie unter source_files .

.und ..sind Verzeichnisse bzw. das aktuelle Verzeichnis und das übergeordnete Verzeichnis. Für die Shell ist beides nicht besonders, daher ist beides nicht von der Erweiterung betroffen, und das Verzeichnis wird einschließlich versteckter Dateien kopiert. *Auf der anderen Seite wird es zu einer Liste von Dateien erweitert, und hier werden versteckte Dateien herausgefiltert.

src/.ist das aktuelle Verzeichnis in srcdem es srcsich befindet; src/src_dir/..ist src_dirdas übergeordnete Verzeichnis von src. Also von außen src, wenn srcein Verzeichnis ist , Angabe src/.oder src/src_dir/..als Quelldatei für cpgleichwertig sind, und kopieren Sie den Inhalt src, einschließlich versteckte Dateien.

Der Punkt der Angabe src/.ist, dass es fehlschlagen wird, wenn srces sich nicht um ein Verzeichnis (oder eine symbolische Verknüpfung zu einem Verzeichnis) handelt, wohingegen srcdies nicht der Fall ist . Es kopiert auch nur den Inhalt von src, ohne sich srcselbst zu kopieren . das passt auch zur Dokumentation:

Wenn target vorhanden ist und ein vorhandenes Verzeichnis benennt, besteht der Name des entsprechenden Zielpfads für jede Datei in der Dateihierarchie aus der Verkettung von target , einem einzelnen Schrägstrich, wenn target nicht mit einem Schrägstrich endete, und dem Pfadnamen der relativen Datei in das Verzeichnis mit der Quelldatei .

So cp -R src/. destkopiert den Inhalt des srczu dest/.(die Quelldatei .in src), während cp -R src destkopiert den Inhalt des srczu dest/src(die Quelldatei src).

Eine andere Möglichkeit, sich das vorzustellen, besteht darin, das Kopieren src/src_dirund src/.nicht das Vergleichen src/.und zu vergleichen src. .verhält sich genauso wie src_dirim ersteren Fall.

Stephen Kitt
quelle
Aber es verhält sich nicht so. Angeben srcdes Verzeichnisses in kopiert dest, src/.wird der Inhalt kopieren. Ich werde versuchen, das in der Frage klarer zu machen.
iFreilicht
Ich denke, das beantwortet Ihre zugrunde liegende Frage.
Stephen Kitt
1
@ Stéphane das OP vergleicht das Kopieren src/.und src/*(; beachte, nicht src/.* ); src/*Enthält keine versteckten Dateien, wenn Globbing sie ignoriert ...
Stephen Kitt
1
Hmm, "Verzeichnis mit Quelldatei ". Natürlich srcenthält, src/.aber es bedeutet, dass das enthaltende Verzeichnis eines Verzeichnisses davon abhängt, wie Sie das Verzeichnis benennen. Natürlich bedeutet das Vorhandensein der .Links in gewisser Weise, dass alle Verzeichnisse sich selbst enthalten, aber das ist möglicherweise nicht für alle intuitiv. Anstelle dieses Verhaltens könnte man auch davon ausgehen, dass "das Verzeichnis, das das Verzeichnis enthält foo" bestimmt wird foo/... In diesem Fall spielt es keine Rolle, ob wir auf foooder verweisen foo/.: Das resultierende enthaltende Verzeichnis wäre dasselbe.
ilkkachu
1
Das heißt, die Unterscheidung zwischen foound foo/.scheint ein bisschen heikel, aber es macht mir nichts aus, ich finde es auch etwas amüsant.
ilkkachu
1

Wenn du rennst cp -R src/foo dest, wirst du bekommen dest/foo. Wenn das Verzeichnis dest/foonicht vorhanden ist, cpwird es erstellt und anschließend der Inhalt von src/foonach kopiert dest/foo.

Wenn du rennst cp -R src/. dest, siehst du , cpdass dest/.es das gibt, und dann geht es nur darum, den Inhalt von src/.to zu kopieren dest/..

Wenn Sie denken , es als ein Verzeichnis kopiert Namen .von srcund dessen Inhalt mit dem bestehenden Verzeichnis verschmelzenden dest/., wird es Sinn machen.

telcoM
quelle