Warum verhält sich „cp -ra/. b“ so, wie es sich verhält?

Warum verhält sich „cp -ra/. b“ so, wie es sich verhält?

Das dachte ich mir aund es a/.ist der gleiche Weg. Allerdings habe ich festgestellt, dasscpUndrsynckopiert den Verzeichnisinhalt statt des Verzeichnisses selbst, wenn /.es zum Quellpfad hinzugefügt wird. Ich habe es auch versucht a/inner/..; das hat auch funktioniert.

$ cp -r a b  # Copies dir a into dir b.
$ cp -r a/. b  # Copies files from dir a into dir b.
$ cp -r a/inner/.. b  # Also copies files from dir a into dir b.
$ cd a && cp -r . ../b  # One more way to copy inner files.

Ich verstehe, dass das nützlich ist. Aber ich bin etwas verwirrt, weil diese Funktion anscheinend Standards verletzt.

Wie funktioniert das? Ist diese Funktion irgendwo dokumentiert? Ist dies eine Funktion des Betriebssystems,cpoder bashen?

Antwort1

Ich verstehe, dass das nützlich ist. Aber ich bin etwas verwirrt, weil diese Funktion anscheinend Standards verletzt.

cpDas Verhalten beim rekursiven Kopieren von a/.nach bstimmt vollkommen mit seinem „normalen“ Verhalten überein.

Standardmäßig,cperstellt keine übergeordneten Verzeichnisse. Dies kann mit demElternschalten:

   --parents
          use full source file name under DIRECTORY

Aber was bedeutet das?

Das bedeutet, dass der Befehl

cp --parents -r some/path/to/source dest

kopiert den Inhalt des Quellverzeichnisses in dest/some/path/to/source, der Befehl

cp -r some/path/to/source dest

kopiert den Inhalt des Quellverzeichnisses in dest/source.

Ebenso der Befehl

cp -r some/path/to/source/. dest

kopiert den Inhalt des Quellverzeichnisses in dest/., was einfach ist dest.

Dachte ich, aund a/.es ist der gleiche Weg.

aUnda/. Istden gleichen Weg. Aber als Argument fürcp, es ist nur eine Zeichenfolge.

Beachten Sie, dass die Befehle

cp --parents -r some/path/to/source dest

Und

cd some/path/to && cp --parents -r source dest

wird sich auch anders verhalten.


Was ist mit cp -r a/inner/.. b? Sollte es unter Berücksichtigung Ihrer Erklärung nicht Dateien dorthin kopieren b/..(also in das aktuelle Verzeichnis)?

Nun ja. Dies ist eine Ausnahme.

Zumindest in der GNU-Version voncp, es gibt einen Sonderfall für den ..Basisnamen.

Auscoreutils-8.22/src/cp.c:

          if (parents_option)
            {
              [removed]
            }
          else
            {
              char *arg_base;
              /* Append the last component of 'arg' to 'target_directory'.  */

              ASSIGN_BASENAME_STRDUPA (arg_base, arg);
              /* For 'cp -R source/.. dest', don't copy into 'dest/..'. */
              dst_name = (STREQ (arg_base, "..")
                          ? xstrdup (target_directory)
                          : file_name_concat (target_directory, arg_base,
                                              NULL));
            }

Die Motivation scheint darin zu liegen, das Kopieren außerhalb des Zielordners zu vermeiden, was – obwohl es vollkommen im Einklang mitcpDas Verhalten von in allen anderen Fällen – ist ein wenig kontraintuitiv und könnte unangenehme Folgen haben.

Schließlich glaube ich nicht, dass irgendjemand den Befehl erwarten würde

cp -r .. ~

um Dateien außerhalb seines Home-Verzeichnisses zu beeinflussen ...

Antwort2

$ mkdir a b a/inner
$ touch a/a{1..3} b/b{1..3}
$ ls -R
.:
a  b

./a:
a1  a2  a3  inner

./a/inner:

./b:
b1  b2  b3
$ cp a b
cp: omitting directory ‘a’
$ cp a/. b
cp: omitting directory ‘a/.’
$ cp a/inner/.. b
cp: omitting directory ‘a/inner/..’
$ cd a && cp . ../b
cp: omitting directory ‘.’
$ cd ..
$ ls -R
.:
a  b

./a:
a1  a2  a3  inner

./a/inner:

./b:
b1  b2  b3

Nichts von dem, was Sie sagen, passiert tatsächlich. Die vier cpBefehle tun nichts. Vielleicht haben Sie einen Alias ​​für „ cploaded“. Sie können dies mit überprüfen alias cp.

Antwort3

Apropos rsync(1), lesen Sie das Handbuchsorgfältig. Es werden einige ungewöhnliche Konventionen verwendet, um „den Inhalt des Verzeichnisses“ gegenüber „das Verzeichnis und seinen Inhalt“ zu bezeichnen.

Für cp(1)und andere Linux-Befehle, an derKernelEbene aund a/.und verweisen sogar a/inner/..auf genau dasselbe Verzeichnis. Das bedeutet nicht, dass die Anwendung sie nicht selbst analysieren und ihnen unterschiedliche Bedeutungen geben kann, aber es ist einfacher, die Zeichenfolge einfach an den Kernel zu senden, der das Richtige tut.

Antwort4

Wenn ich mich recht erinnere, funktioniert das . in diesem Fall ähnlich wie ein *. Im Wesentlichen ist es ein Platzhalterzeichen.

verwandte Informationen