Скопіюйте певний тип файлу, зберігаючи структуру папки


108

У мене структура папки з купою файлів * .csv, розкиданих по папках. Тепер я хочу скопіювати всі * .csv файли в інше місце призначення, зберігаючи структуру папки.

Це працює, виконуючи:

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

і так далі, але я хотів би це зробити за допомогою однієї команди.

Відповіді:


126

Чи є причина, чому люди чинять опір використанню знахідки -exec? Це дуже зручно.

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

Знайте свої інструменти. ;-)


62
Можливо, через це \ {\} \;
igo

12
'{}'працює так само добре
OrangeDog

3
Незважаючи на те, що -execdirце безпечніше -exec, просто заміна однієї іншої не зберігає структуру папки за призначенням.
Simon Shine

2
Чому я отримую повідомлення "Опускаючи каталог", коли я намагаюся скопіювати їх за допомогою вашої команди?
Вікі Дев

4
Чи можете ви пояснити, чому тут потрібно уникати брекетів?
Номенон

46

Ви також можете використовувати rsyncдля цього.

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

Якщо ви хочете зберегти порожні каталоги з вихідного дерева, пропустіть --prune-empty-dirsпараметр:

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

Якщо ви не хочете, щоб символьні посилання, дати модифікації, дозволи на файли, власники тощо зберігалися, будь ласка, замініть -aна іншу комбінацію -rlptgoD. ;-)


1
-m- це ярлик для --prune-emty-dirs.
Геремія

Також -Rможе бути додана опція для копіювання структури батьківського каталогу джерела. (пор. моя відповідь тут.)
Геремія

-R працює для мене! Спасибі
gigi2

32

Ви можете використовувати find і cpio в режимі проходження через

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

Це знайде всі .csv файли в поточному каталозі та нижче та скопіює їх у / target, підтримуючи вбудовану структуру каталогу ..

Якщо ви використовуєте

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

він знайде весь файл усередині /path/to/filesта нижче та скопіює їх у /target/path/to/filesта нижче.


3
Я спробував усі відповіді зверху до цієї, і це був єдиний, хто працював над першою спробою
OscarRyz

21

cpКоманда дозволяє множинні аргументи джерела:

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

CAVEAT: я тут використовую рекурсивний глобус; ця globstarопція в Bash 4+ і ksh, і підтримується за замовчуванням у zsh. Рекурсивні глобуси не відповідають прихованим файлам і папкам, а деякі реалізації слідують за посиланнями, а інші - ні .

Якщо ваша оболонка не підтримує рекурсивні глобуси або ви хочете не використовувати їх, ви можете зробити наступне:

  • *.csv */*.csv */*/*.csv */*/*/*.csv - це, звичайно, дуже зайве і вимагає знати, наскільки глибока структура вашого каталогу.
  • $(find . -name '*.csv')- Це буде відповідати приховані файли і папки. findтакож підтримує вказівку, чи слід дотримуватися символьних посилань, що може бути корисно.

це саме те, що я спробував (рекурсивний глобус), і він знайшов деякі, але не всі? досить дивно. Я отримав такий самий точний результат при використанні сценарію npm copyfiles, але якщо я використовую команду find, він знайде все ...
Randyaa

@Randyaa Мені потрібні ще деякі подробиці про те, які саме файли не були знайдені, щоб допомогти тобі. Ви можете знайти дискусію тут і продовжити тут про точну поведінку рекурсивного глобального корисного.
Кайл Странд

1
виявляється, рекурсивний глобус чомусь не був увімкнутий ... Я ніколи раніше не стикався з цим, але я виправив це лише виконанням shopt -s globstarбезпосередньо перед моєю командою, і все добре. Дякуємо за подальші дії!
Randyaa

--parentsбуло те, що я шукав. дякую
Джош

17

Цей працював на мене:

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


Найкраща відповідь із найпростішим синтаксисом. Працює чудово і легко запам'ятовується. У багатьох випадках find [things] | xargs [do stuff]це дуже потужно.
Щоденний астронавт

Домовились. Дуже прямо, порівняно з деякими іншими відповідями.
Тім Б

1
Перерви, якщо у вас є пробіли у іменах
Мішель Піколіні

@MichelePiccolini Проміжки у іменах файлів можна обробляти за допомогою find -print0та xargs -0.
pasztorpisti

8

Припускаючи , що ви хочете , щоб повторити цю структуру від ./sourceдо ./destination:

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

Я готовий рахувати це як один рядок, cd sourceбудучи оболонкою.


2
Я не думаю, що він насправді має на увазі одну команду - просто не треба пхатись, як його приклад;)

tarмає -Cможливість уникнути необхідності спочатку змінити каталог.
барт

8

З сайту rsyncman:

-R, - відносна

Використовуйте відносні шляхи. Це означає, що повні імена шляху, вказані в командному рядку, надсилаються на сервер, а не лише в останні частини файлових імен. Це особливо корисно, коли ви хочете одночасно надсилати кілька різних каталогів. Наприклад, якщо ви використовували цю команду:

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

... це створило би файл на ім'я baz.c в / tmp / на віддаленій машині. Якщо замість цього ви використовували

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

тоді на віддаленій машині буде створений файл з назвою /tmp/foo/bar/baz.c, зберігши повний шлях. Ці додаткові елементи шляху називаються "імпліцитними каталогами" (тобто каталоги "foo" та "foo / bar" у наведеному вище прикладі).

Отже, це також спрацює:

rsync -armR --include="*/" --include="*.csv" --exclude="*" /full/path/to/source/file(s) destination/
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.