631 Stimmen

Linux: Kopieren und Erstellen des Zielverzeichnisses, wenn es nicht existiert

Ich möchte einen Befehl (oder wahrscheinlich eine Option für cp), der das Zielverzeichnis erstellt, wenn es nicht existiert.

Beispiel:

cp -? file /path/to/copy/file/to/is/very/deep/there

9 Stimmen

Die akzeptierte Antwort ist falsch (es gibt eine solche Option für cp). Siehe zweite Antwort von Paul Whipp.

1 Stimmen

@Ronenz, ich stimme zu, dass es eine erwähnenswerte Option in GNU gibt cp (wie von Paul Whipp beantwortet), aber es ist nicht so allgemein, wie es der OP wollte. Sie kann kopieren a/foo/bar/file まで b/foo/bar/file aber er kann nicht kopieren file まで b/foo/bar/file . (d. h. es funktioniert nur, um übergeordnete Verzeichnisse zu erstellen, die im Fall der ersten Datei bereits vorhanden waren, aber es kann keine beliebigen Verzeichnisse erstellen)

630voto

Michael Krelin - hacker Punkte 130575
mkdir -p "$d" && cp file "$d"

(es gibt keine solche Option für cp ).

67 Stimmen

Ich glaube nicht, dass Sie die test -d : mkdir -p ist auch dann erfolgreich, wenn das Verzeichnis bereits existiert.

1 Stimmen

Oops, richtig. Aber dann kann test ein Bash-Builtin sein (besonders wenn es als [[ -d "$d" ]] geschrieben wird) und mkdir nicht ;-)

1 Stimmen

mkdir ist eine eingebaute Funktion in BusyBox ;)

343voto

Paul Whipp Punkte 14811

Wenn beide der folgenden Punkte zutreffen:

  1. Sie verwenden die GNU-Version von cp (und nicht zum Beispiel die Mac-Version), und
  2. Sie kopieren von einer bestehenden Verzeichnisstruktur und müssen diese lediglich neu erstellen

dann können Sie dies mit dem --parents Flagge von cp . Von der Infoseite (einsehbar unter http://www.gnu.org/software/coreutils/manual/html_node/cp-invocation.html#cp-invocation oder mit info cp o man cp ) :

--parents
     Form the name of each destination file by appending to the target
     directory a slash and the specified name of the source file.  The
     last argument given to `cp' must be the name of an existing
     directory.  For example, the command:

          cp --parents a/b/c existing_dir

     copies the file `a/b/c' to `existing_dir/a/b/c', creating any
     missing intermediate directories.

Beispiel:

/tmp $ mkdir foo
/tmp $ mkdir foo/foo
/tmp $ touch foo/foo/foo.txt
/tmp $ mkdir bar
/tmp $ cp --parents foo/foo/foo.txt bar
/tmp $ ls bar/foo/foo
foo.txt

5 Stimmen

Dies funktioniert nicht unter Mac OS X, also ist es wohl Linux-spezifisch.

11 Stimmen

Ich würde sagen, gnu-spezifisch. Wenn Sie macports können Sie die coreutils und ihre gcp .

45 Stimmen

Mann, Linux hat alles

155voto

Mark Amery Punkte 124946

Kurze Antwort

Zum Kopieren myfile.txt a /foo/bar/myfile.txt verwenden:

mkdir -p /foo/bar && cp myfile.txt $_

Wie funktioniert das?

Da dies aus mehreren Komponenten besteht, werde ich die gesamte Syntax Schritt für Schritt erläutern.

Le site mkdir Nutzen, wie im POSIX-Standard festgelegt , macht Verzeichnisse. Die -p Argument, wie in der Dokumentation beschrieben, bewirkt mkdir zu

Erstellen Sie alle fehlenden Zwischenpfadkomponenten

was bedeutet, dass beim Aufruf von mkdir -p /foo/bar , mkdir wird erstellt /foo und /foo/bar si /foo nicht bereits vorhanden ist. (Ohne -p wird stattdessen ein Fehler ausgegeben.

Le site && Listenoperator, wie in der Dokumentation POSIX-Standard (oder die Bash-Handbuch wenn Sie das bevorzugen), hat den Effekt, dass cp myfile.txt $_ wird nur ausgeführt, wenn mkdir -p /foo/bar wird erfolgreich ausgeführt. Dies bedeutet, dass die cp Befehl wird nicht versucht auszuführen, wenn mkdir versagt bei einer der vielen Gründe, warum es scheitern könnte .

Schließlich ist die $_ übergeben wir als zweites Argument an cp ist ein "spezieller Parameter", der nützlich sein kann, um die Wiederholung langer Argumente (wie Dateipfade) zu vermeiden, ohne sie in einer Variablen speichern zu müssen. Per das Bash-Handbuch , it:

wird auf das letzte Argument des vorherigen Befehls erweitert

In diesem Fall ist das die /foo/bar haben wir an mkdir . Also die cp wird der Befehl erweitert zu cp myfile.txt /foo/bar , die Kopien myfile.txt in die neu erstellte /foo/bar Verzeichnis.

Beachten Sie, dass $_ es no Teil des POSIX-Standards so dass theoretisch eine Unix-Variante eine Shell haben könnte, die dieses Konstrukt nicht unterstützt. Ich kenne jedoch keine modernen Shells, die dieses Konstrukt nicht unterstützen. $_ Bash, Dash und zsh tun dies auf jeden Fall.


Ein letzter Hinweis: Der Befehl, den ich am Anfang dieser Antwort gegeben habe, setzt voraus, dass Ihre Verzeichnisnamen keine Leerzeichen enthalten. Wenn Sie es mit Namen mit Leerzeichen zu tun haben, müssen Sie diese in Anführungszeichen setzen, damit die verschiedenen Wörter nicht als unterschiedliche Argumente für mkdir o cp . Ihr Befehl würde also wie folgt aussehen:

mkdir -p "/my directory/name with/spaces" && cp "my filename with spaces.txt" "$_"

37 Stimmen

Nebenbei bemerkt: Ich bin normalerweise enttäuscht über den Mangel an Details in Fragen über Bash- oder Unix-Shell-Befehle auf Stack Overflow, die oft einen komplizierten und extrem dichten Einzeiler ausgeben, der schwer zu entschlüsseln ist, wenn man nicht bereits ein Unix-Experte ist. Ich habe versucht, hier das entgegengesetzte Extrem zu wählen und sowohl jedes Detail der Syntax zu erklären als auch auf die entsprechenden Stellen zu verlinken, an denen man Dokumentation darüber findet, wie dieses Zeug funktioniert. Ich hoffe, das hilft wenigstens einigen Leuten. Außerdem, Ehre, wem Ehre gebührt: Ich habe diesen Ansatz von dieser Antwort auf eine doppelte Frage geklaut: stackoverflow.com/a/14085147/1709587

0 Stimmen

Ich habe $_ noch nie gesehen. Worauf bezieht es sich? auf den im letzten Befehl verwendeten Ordner?

18 Stimmen

@thebunnyrules Aber... aber... es gibt eine "Wie funktioniert das?" Abschnitt in meiner Antwort, der buchstäblich mehrere Absätze enthält, die speziell der Frage gewidmet sind, die Sie gerade gestellt haben. Ich fühle mich ignoriert und ungeliebt :(

70voto

help_asap Punkte 694

Das ist eine alte Frage, aber vielleicht kann ich eine alternative Lösung vorschlagen.

Sie können die install Programm, um Ihre Datei zu kopieren und den Zielpfad "on the fly" zu erstellen.

install -D file /path/to/copy/file/to/is/very/deep/there/file

Es gibt jedoch einige Aspekte, die zu beachten sind:

  1. müssen Sie auch den Namen der Zieldatei angeben nicht nur den Zielpfad
  2. die Zieldatei wird ausführbar sein (zumindest, soweit ich das bei meinen Tests feststellen konnte)

Sie können die #2 leicht ändern, indem Sie die -m um die Berechtigungen für die Zieldatei festzulegen (Beispiel: -m 664 erstellt die Zieldatei mit den Rechten rw-rw-r-- genauso wie das Erstellen einer neuen Datei mit touch ).


Und hier ist sie die schamloser Link zu der Antwort, die mich inspiriert hat \=)

5 Stimmen

Beachten Sie, dass dieser Befehl die Zieldateien mit 755 ( rwxr-xr-x ), was wahrscheinlich nicht erwünscht ist. Sie können etwas anderes mit der Option -m Schalter, aber ich konnte keine Möglichkeit finden, einfach behalten. die Dateiberechtigungen :(

1 Stimmen

Um die korrekten Dateibesitzverhältnisse/Masken sicherzustellen: install -D /path/to/source /path/to/dest/dir -o some-user -m 0754

29voto

Andy Ross Punkte 11205

Shell-Funktion, die genau das tut, was Sie wollen. Sie wird "bury" genannt, weil sie ein Loch gräbt, in dem die Datei leben soll:

bury_copy() { mkdir -p `dirname $2` && cp "$1" "$2"; }

1 Stimmen

Sie sollten Anführungszeichen um das dirname $2 zu

4 Stimmen

@Kalmi, um richtig zu zitieren, sollten Sie auch zitieren $2 als Argument für dirname . Wie mkdir -p "$(dirname "$2")" . Ohne diese Anführung $2 en cp ist nutzlos ;)

3 Stimmen

Beachten Sie, dass diese Antwort davon ausgeht, dass $2 nicht bereits das Zielverzeichnis ist, andernfalls würden Sie einfach "mkdir -p "$2" && cp "$1" "$2" als Funktionskörper verwenden

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X