Skopiuj określony typ pliku zachowując strukturę folderów

108

Mam strukturę folderów z wieloma plikami * .csv rozrzuconymi po folderach. Teraz chcę skopiować wszystkie pliki * .csv do innego miejsca docelowego, zachowując strukturę folderów.

Działa poprzez:

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

i tak dalej, ale chciałbym to zrobić za pomocą jednego polecenia.

Wilfred Hughes
źródło

Odpowiedzi:

126

Czy jest jakiś powód, dla którego ludzie nie chcą używać find's -exec? To bardzo przydatne.

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

Poznaj swoje narzędzia. ;-)

msb
źródło
62
Prawdopodobnie z tego powodu \ {\} \;
igo
12
'{}'działa równie dobrze
OrangeDog
3
Chociaż -execdirjest to bezpieczniejsze niż -execzwykłe zastąpienie jednego z drugim nie zachowuje struktury folderów zgodnie z przeznaczeniem.
Simon Shine
2
Dlaczego pojawia się komunikat „Pominięcie katalogu”, gdy próbuję skopiować je za pomocą polecenia?
Vicky Dev,
4
Czy potrafisz wytłumaczyć, dlaczego trzeba tutaj uciec?
Noumenon
46

Możesz również użyć rsyncdo tego.

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

Jeśli chcesz zachować puste katalogi z drzewa źródłowego, pomiń --prune-empty-dirsopcję:

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

Jeśli nie chcesz zachować dowiązań symbolicznych, dat modyfikacji, uprawnień do plików, właścicieli itp., Zamień na -ainną kombinację -rlptgoD. ;-)

Dubu
źródło
1
-mjest skrótem do --prune-emty-dirs.
Geremia
Można także -Rdodać opcję kopiowania struktury katalogu nadrzędnego źródła. (por. moja odpowiedź tutaj.)
Geremia,
-R działa dla mnie! Dzięki
gigi2
32

Możesz użyć funkcji Znajdź i CPIO w trybie przejścia

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

To znajdzie wszystkie pliki .csv w bieżącym katalogu i poniżej i skopiuje je do / target, utrzymując strukturę katalogu zakorzenioną ..

Jeśli użyjesz

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

znajdzie wszystkie pliki w /path/to/filesi poniżej oraz skopiuje je do /target/path/to/filesi poniżej.


źródło
3
Próbowałem wszystkich odpowiedzi od góry do góry, i to była jedyna, która zadziałała przy pierwszej próbie
OscarRyz
21

cpPolecenie zezwala wiele argumentów źródłowych:

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

CAVEAT: Używam tutaj globu rekurencyjnego; jest to globstaropcja w Bash 4+ kshi jest domyślnie obsługiwana w zsh. Globy rekurencyjne nie pasują do ukrytych plików i folderów, a niektóre implementacje podążają za dowiązaniami symbolicznymi, a inne nie .

Jeśli twoja powłoka nie obsługuje rekurencyjnych globów lub wolisz ich nie używać, możesz wykonać następujące czynności:

  • *.csv */*.csv */*/*.csv */*/*/*.csv - jest to oczywiście bardzo zbędne i wymaga znajomości głębokości struktury katalogów.
  • $(find . -name '*.csv')- To będzie dopasować ukryte pliki i foldery. findobsługuje także określanie, czy mają być stosowane dowiązania symboliczne, co może być przydatne.
Kyle Strand
źródło
właśnie tego próbowałem (glob rekurencyjny) i znalazłem niektóre, ale nie wszystkie? dość dziwne. Ten sam dokładny wynik uzyskałem przy użyciu skryptu npm copyfiles, ale jeśli użyję polecenia find, to wszystko znajdzie ...
Randyaa,
@ Randyaa Potrzebuję więcej szczegółów na temat tego, które pliki nie zostały znalezione, aby ci pomóc. Można znaleźć dyskusję tutaj i nadal tu o precyzyjne zachowanie rekurencyjnego glob użytecznego.
Kyle Strand,
1
okazuje się, że glob globalny rekurencyjny nie został włączony z jakiegoś powodu ... Nigdy wcześniej na to nie wpadłem, ale poprawiłem go wykonując shopt -s globstarpolecenie tuż przed moim poleceniem i wszystko jest w porządku. Dzięki za kontynuację!
Randyaa,
--parentstego szukałem. dzięki
Josh
17

Ten działał dla mnie:

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

marko
źródło
Najlepsza odpowiedź z najprostszą składnią. Działa dobrze i jest łatwy do zapamiętania. W wielu przypadkach find [things] | xargs [do stuff]jest bardzo potężny.
Codziennie astronauta
Zgoda. Bardzo proste w porównaniu do niektórych innych odpowiedzi.
Tim B
1
Łamie się, jeśli masz spacje w nazwach plików
Michele Piccolini
@MichelePiccolini Spacje w nazwach plików mogą być obsługiwane za pomocą find -print0i xargs -0.
pasztorpisti
8

Zakładając, że chcesz powtórzyć tę strukturę od ./sourcedo ./destination:

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

Jestem gotów policzyć to jako jedną linię, ponieważ cd sourcejest to wbudowana powłoka.

Szalony Kapelusznik
źródło
2
Nie sądzę, żeby naprawdę miał na myśli jedno polecenie - po prostu nie trzeba się pieprzyć jak jego przykład;)
tarma -Copcję uniknięcia pierwszej zmiany katalogu.
Bart
8

Z rsyncstrony podręcznika:

-R, - względne

Użyj ścieżek względnych. Oznacza to, że pełne nazwy ścieżek określone w wierszu poleceń są wysyłane na serwer, a nie tylko ostatnie części nazw plików. Jest to szczególnie przydatne, gdy chcesz wysłać kilka różnych katalogów jednocześnie. Na przykład, jeśli użyłeś tego polecenia:

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

... utworzy to plik o nazwie baz.c w / tmp / na zdalnym komputerze. Jeśli zamiast tego użyłeś

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

następnie plik o nazwie /tmp/foo/bar/baz.c zostanie utworzony na komputerze zdalnym, zachowując pełną ścieżkę. Te dodatkowe elementy ścieżki są nazywane „katalogami domyślnymi” (tj. Katalogami „foo” i „foo / bar” w powyższym przykładzie).

To też by działało:

rsync -armR --include="*/" --include="*.csv" --exclude="*" /full/path/to/source/file(s) destination/
Geremia
źródło