Копировать определенный тип файла, сохраняя структуру папок

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 \;

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

MSB
источник
62
Вероятно, из-за этого \ {\} \;
иго
12
'{}'работает так же хорошо
OrangeDog
3
Даже если -execdirэто безопаснее, чем -execпросто заменить одну на другую, структура папок не будет сохранена должным образом.
Саймон Шайн
2
Почему я получаю сообщение «Пропускать каталог», когда пытаюсь скопировать их с помощью вашей команды?
Вики Дев
4
Можете ли вы объяснить, почему здесь следует избегать брекетов?
Нумен
47

Вы также можете использовать 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. ;-)

Dubu
источник
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

ПРЕДУПРЕЖДЕНИЕ: я использую рекурсивный шар здесь; это globstarопция в Bash 4+ kshи поддерживается по умолчанию в zsh. Рекурсивные глобусы не соответствуют скрытым файлам и папкам, и некоторые реализации следуют символическим ссылкам, а другие - нет .

Если ваша оболочка не поддерживает рекурсивные глобусы или вы не хотите их использовать, вы можете сделать следующее:

  • *.csv */*.csv */*/*.csv */*/*/*.csv - это, конечно, очень избыточно и требует знания глубины структуры вашего каталога.
  • $(find . -name '*.csv')- Это будет соответствовать скрытым файлам и папкам. findтакже поддерживает указание, следует ли использовать символические ссылки, что может быть полезно.
Кайл Стрэнд
источник
это именно то, что я пытался (рекурсивный шар), и он нашел некоторые, но не все? довольно странно Я получил такой же точный результат при использовании скрипта npm copyfiles, но если я использую команду find, он находит все ...
Randyaa
@Randyaa Мне понадобятся дополнительные сведения о том, какие именно файлы не были найдены, чтобы помочь вам. Вы можете найти обсуждение здесь и продолжение здесь о точном поведении рекурсивного глобуса полезным.
Кайл Стрэнд,
1
Оказывается, рекурсивный глобус не был включен по какой-то причине ... Я никогда не сталкивался с этим раньше, но я исправил это, просто выполнив shopt -s globstarнепосредственно перед моей командой, и все хорошо. Спасибо за продолжение!
Рандя
--parentsбыло то, что я искал. спасибо
Джош
17

Этот работал для меня:

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

Marko
источник
Лучший ответ с самым простым синтаксисом. Работает просто отлично и легко запоминается. Во многих случаях 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

Из rsyncсправочной страницы:

-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/
Geremia
источник