Скопируйте все файлы с определенным расширением из всех подкаталогов

112

В unix я хочу скопировать все файлы с определенным расширением (все файлы Excel) из всех подкаталогов в другой каталог. У меня есть такая команда:

cp --parents `find -name \*.xls*` /target_directory/

Проблемы с этой командой:

  • Он также копирует структуру каталогов, и мне нужны только файлы (поэтому все файлы должны находиться в / target_directory /)

  • Он не копирует файлы с пробелами в именах файлов (а их довольно много)

Какие решения этих проблем?

Абдель
источник
О чем find... exec mv?
fedorqui «SO, перестань причинять вред»

Ответы:

174

--parents копирует структуру каталогов, поэтому вам следует избавиться от этого.

То, как вы это написали, findвыполняет, а вывод помещается в командную строку, так что cpне может различить пробелы, разделяющие имена файлов, и пробелы внутри имени файла. Лучше сделать что-нибудь вроде

$ find . -name \*.xls -exec cp {} newDir \;

в котором cpвыполняется для каждого найденного findимени файла и правильно передано имя файла. Подробнее об этой технике.

Вместо всего вышеперечисленного вы можете использовать zsh и просто ввести

$ cp **/*.xls target_directory

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

Брайан Агнью
источник
2
Да. «убрать это» означает выбросить. Теперь исправлено :-)
Брайан Агнью
13
Bash4.0+, а ksh93также поддерживает **. Для bash используйте, shopt -s globstarчтобы включить его. Для ksh это set -Gили set -o globstar.
pynexj
2
@Daryl - я заполнил дальше. Но ответ уже был помечен как «принят», примечание
Брайан Агнью
5
Этот exec технически менее эффективен, чем передача в xargs, который сделает все это за как можно меньше вызовов cp: find . -name '*.xls' -print0 | xargs -0 cp -t destdir
Taywee 01
2
@BrianAgnew О, я уверен, просто хорошо, что в комментариях есть дополнительная информация для своенравных гуглеров.
Taywee 01
37

Из всего вышеперечисленного я придумал эту версию. Эта версия также работает у меня в терминале восстановления Mac.

find ./ -name '*.xsl' -exec cp -prv '{}' '/path/to/targetDir/' ';'

Он будет искать файлы с расширением xsl в текущем каталоге и рекурсивно во всех подкаталогах. Он скопирует их все в целевой каталог.

cp флаги:

  • p - сохранить атрибуты файла
  • r - рекурсивный
  • v - подробный (показывает, что копируется)
гуя
источник
1
Это то же самое, что я должен был сделать, когда SSH подключился к Bluehost.
Пламмер
4
Он НЕ сохраняет поддиапазоны.
b005t3r
3
@ b005t3r, то есть по замыслу, этого не должно быть. В этом весь смысл вопроса ОП. Он хотел, чтобы все файлы из подкаталогов были скопированы в один каталог без подкаталогов
Madivad
2
Есть ли способ изменить это, чтобы сохранить подкаталоги?
Мэтью Дин,
8

У меня была похожая проблема. Я решил это, используя:

find dir_name '*.mp3' -exec cp -vuni '{}' "../dest_dir" ";"

'{}'И ";"выполняет копию на каждый файл.

жалоMantis
источник
3

Мне тоже пришлось это делать самому. Я сделал это с помощью аргумента --parents для cp:

find SOURCEPATH -name filename*.txt -exec cp --parents {} DESTPATH \;
Этот парень
источник
1
find [SOURCEPATH] -type f -name '[PATTERN]' | 
    while read P; do cp --parents "$P" [DEST]; done

вы можете удалить параметр --parents, но существует риск коллизии, если несколько файлов имеют одно и то же имя.

Камион
источник