Kopieren Sie einen bestimmten Dateityp unter Beibehaltung der Ordnerstruktur

108

Ich habe eine Ordnerstruktur mit einer Reihe von * .csv-Dateien, die über die Ordner verteilt sind. Jetzt möchte ich alle * .csv-Dateien an einen anderen Speicherort kopieren und dabei die Ordnerstruktur beibehalten.

Es funktioniert folgendermaßen:

cp --parents *.csv /target
cp --parents */*.csv" /target
cp --parents */*/*.csv /target
cp --parents */*/*/*.csv /target
...

und so weiter, aber ich möchte es mit einem Befehl tun.

Wilfred Hughes
quelle

Antworten:

126

Gibt es einen Grund, warum die Leute sich weigern, Funde zu benutzen -exec? Es ist sehr praktisch.

find . -name '*.csv' -exec cp --parents \{\} /target \;

Kennen Sie Ihre Werkzeuge. ;-)

msb
quelle
62
Wahrscheinlich deswegen \ {\} \;
igo
12
'{}'funktioniert genauso gut
OrangeDog
3
Auch wenn dies -execdirsicherer ist als -exec: Durch einfaches Ersetzen der Ordner bleibt die Ordnerstruktur nicht wie vorgesehen erhalten.
Simon Shine
2
Warum erhalte ich die Meldung "Verzeichnis auslassen", wenn ich versuche, sie mit Ihrem Befehl zu kopieren?
Vicky Dev
4
Können Sie erklären, warum die Klammern hier entkommen müssen?
Noumenon
46

Sie könnten auch dafür verwenden rsync.

$ rsync -a --prune-empty-dirs --include '*/' --include '*.csv' --exclude '*' source/ target/

Wenn Sie leere Verzeichnisse aus dem Quellbaum behalten möchten, überspringen Sie die --prune-empty-dirsOption:

$ rsync -a --include '*/' --include '*.csv' --exclude '*' source/ target/

Wenn Sie nicht möchten, dass Symlinks, Änderungsdaten, Dateiberechtigungen, Eigentümer usw. erhalten bleiben, ersetzen Sie diese bitte durch eine -aandere Kombination von -rlptgoD. ;-)

Dubu
quelle
1
-mist eine Abkürzung für --prune-emty-dirs.
Geremia
Außerdem kann die -ROption hinzugefügt werden, um die übergeordnete Verzeichnisstruktur der Quelle zu kopieren. (Siehe meine Antwort hier.)
Geremia
-R arbeitet für mich! Danke
gigi2
32

Sie können find und cpio im Pass-Through-Modus verwenden

find . -name '*.csv' | cpio -pdm  /target

Dies findet alle .csv-Dateien im aktuellen Verzeichnis und darunter und kopiert sie nach / target, wobei die Verzeichnisstruktur beibehalten wird, in der sie verwurzelt sind ..

Wenn du benutzt

find /path/to/files -name '*.csv' | cpio -pdm /target

Es findet alle Dateien in /path/to/filesund unter und kopiert sie nach /target/path/to/filesund unter.


quelle
3
Ich habe alle Antworten von oben bis unten ausprobiert, und dies war die einzige, die beim ersten Versuch
funktioniert hat
21

Der cpBefehl lässt mehrere Quellargumente zu:

cp **/*.csv --parents ../target

CAVEAT: Ich verwende hier einen rekursiven Glob. Dies ist die globstarOption in Bash 4+ und kshund wird standardmäßig in unterstützt zsh. Rekursive Globs stimmen nicht mit versteckten Dateien und Ordnern überein. Einige Implementierungen folgen Symlinks, andere nicht .

Wenn Ihre Shell keine rekursiven Globs unterstützt oder Sie diese nicht verwenden möchten, können Sie Folgendes tun:

  • *.csv */*.csv */*/*.csv */*/*/*.csv - Dies ist natürlich sehr redundant und erfordert das Wissen, wie tief Ihre Verzeichnisstruktur ist.
  • $(find . -name '*.csv')- Damit werden versteckte Dateien und Ordner abgeglichen. findunterstützt auch die Angabe, ob Symlinks befolgt werden oder nicht, was nützlich sein kann.
Kyle Strand
quelle
Das ist genau das, was ich ausprobiert habe (der rekursive Glob) und es hat einige gefunden, aber nicht alle? ziemlich komisch. Ich habe das gleiche exakte Ergebnis erhalten, wenn ich das Skript npm copyfiles verwende, aber wenn ich den Befehl find verwende, findet es alles ...
Randyaa
@Randyaa Ich benötige weitere Informationen darüber, welche Dateien genau nicht gefunden wurden, um Ihnen zu helfen. Sie können die Diskussion finden hier und weiter hier über das genaue Verhalten des rekursiven glob nützlich.
Kyle Strand
1
Es stellte sich heraus, dass der rekursive Glob aus irgendeinem Grund nicht aktiviert war ... Ich bin noch nie darauf gestoßen, aber ich habe ihn mit nur einer Ausführung von shopt -s globstarunmittelbar vor meinem Befehl korrigiert, und alles ist in Ordnung. Vielen Dank für das Follow-up!
Randyaa
--parentswar das, wonach ich gesucht habe. Danke
Josh
17

Dieser hat für mich gearbeitet:

find -name "*.csv" | xargs cp --parents -t /target

marko
quelle
Beste Antwort mit einfachster Syntax. Funktioniert einwandfrei und ist leicht zu merken. In vielen Fällen find [things] | xargs [do stuff]ist es sehr kraftvoll.
Jeden Tag Astronaut
Einverstanden. Sehr einfach im Vergleich zu einigen anderen Antworten.
Tim B.,
1
Bricht ab, wenn Sie Leerzeichen in Dateinamen haben
Michele Piccolini
@MichelePiccolini Leerzeichen in Dateinamen können mit find -print0und behandelt werden xargs -0.
Pasztorpisti
8

Angenommen, Sie möchten diese Struktur replizieren von ./sourcenach ./destination:

cd source
find . -name "*.csv" | xargs tar cvf - | (cd ../destination ; tar xfp -)

Ich bin bereit, das als eine einzige Zeile zu zählen, als eine cd sourceeingebaute Shell.

MadHatter
quelle
2
Ich glaube nicht, dass er wirklich einen einzigen Befehl meint - nur, dass er sich nicht wie sein Beispiel
tarhat die -CMöglichkeit, nicht erst das Verzeichnis wechseln zu müssen.
Bart
8

Aus rsyncder Manpage von:

-R, --relativ

Verwenden Sie relative Pfade. Dies bedeutet, dass nicht nur die letzten Teile der Dateinamen, sondern die in der Befehlszeile angegebenen vollständigen Pfadnamen an den Server gesendet werden. Dies ist besonders nützlich, wenn Sie mehrere verschiedene Verzeichnisse gleichzeitig senden möchten. Wenn Sie beispielsweise diesen Befehl verwendet haben:

rsync -av /foo/bar/baz.c remote:/tmp/

... dies würde eine Datei mit dem Namen baz.c in / tmp / auf dem entfernten Rechner erstellen. Wenn Sie stattdessen verwendet haben

rsync -avR /foo/bar/baz.c remote:/tmp/

Anschließend wird auf dem Remote-Computer eine Datei mit dem Namen /tmp/foo/bar/baz.c erstellt, wobei der vollständige Pfad beibehalten wird. Diese zusätzlichen Pfadelemente werden "implizite Verzeichnisse" genannt (dh die Verzeichnisse "foo" und "foo / bar" im obigen Beispiel).

Das würde also auch funktionieren:

rsync -armR --include="*/" --include="*.csv" --exclude="*" /full/path/to/source/file(s) destination/
Geremia
quelle