Как я могу рекурсивно копировать файлы по расширению, сохраняя структуру каталогов?


71

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

Мне нужно, чтобы структура каталогов оставалась неизменной, и мне нужно игнорировать файлы, кроме тех, которые заканчиваются на .txt.


2
Имея в своем вопросе cp и find в качестве тегов, означает ли это, что вы привязаны к этим параметрам? Поскольку ваш набор данных очень большой, имеет смысл предположить, что процесс копирования может быть прерван по некоторым причинам, и вам придется его перезапустить. Я не уверен, что подход find / cp сможет возобновить передачу и скопировать только недостающую часть. Если вы не привязаны к поиску / cp, вы можете рассмотреть rsync, который умнее. Его опция --exclude позволит вам пропустить .txt файлы.
Вторник

Справедливый вызов - rsync, вероятно, является лучшим вариантом. Не привязан к поиску / ср. (Я все равно использовал их - rsync не был установлен на удаленной машине, это был живой веб-сервер, и я хотел оставить как можно меньше места)
невостребованный

Ответы:


96

Вы можете использовать find и cpio для этого

cd /top/level/to/copy
find . -name '*.txt' | cpio -pdm /path/to/destdir

(-updm for overwrite destination content.)

почему м? я думал, что это просто, чтобы сохранить дату изменения файла.
Мубашар

7
cd /source/path
find -type f -name \*.txt -exec install -D {} /dest/path/{} \;

Вы пропустили .после find. Также на macOS 10.13.1 это сработало:find . -type f -name "*.txt" -exec install -v {} /dest/path/{} \;
мрачное

2

Другой подход

find . -name '*.txt' -exec rsync -R {} path/to/dext \;


Мне нравится это решение. Раньше я find . -iname '*.txt' -exec rsync -Rptgon {} path/to/dext \;делал сопоставление без учета регистра и сохранял права собственности и разрешения.
MountainX

1

Самый простой способ, который работал для меня:

cp --parents -R jobs/**/*.xml ./backup/

одна загвоздка в том, что вам нужно перейти в «нужный» каталог, прежде чем «родительский путь» будет правильным.

Также убедитесь, что вы включили рекурсивные глобусы в bash:

shopt -s globstar

1

как насчет того, чтобы сначала скопировать

cp -r /old/folder /new/folder

затем перейдите в новую папку и запустите

find . -type f ! -iname "*.txt" -delete

или просто

cp -r /old/folder /new/folder && find . -type f ! -iname "*.txt" -delete

Изменить: хорошо, вы хотите одну команду, которая фильтрует (я не проверял это, потому что моя система не имеет cpioкоманды!). Вот где я нашел это: http://www.gnu.org/software/findutils/manual/html_mono/find.html#Copying-A-Subset-of-Files

find . -name "*.txt" -print0 |
     cpio -pmd0 /dest-dir

Пожалуйста, сначала проверьте это, потому что я еще не пробовал. Если бы кто-то проверил, это было бы здорово.


кивает Cheers - это будет работать, но без фильтрации в .txt Я смотрю на несколько миллионов файлов (выходят в несколько сотен ГБ). В случае необходимости мне, возможно, придется, но я бы хотел отфильтровать при копировании, если это возможно
невостребованный

1
Приветствия, отредактированная версия работает, если я удаляю '0' из -pmd0
невостребованный

Вы должны держать 0в систему -pmd0и добавить -print0в конец findкоманды ( как раз перед |).
G-Man

1

Я пытался сделать то же самое в macOS, но ни один из вариантов не помог мне. Пока я не обнаружил ditto.

Мне пришлось скопировать много файлов .wav и пропустить видеофайлы ... Итак, вот что я придумала:

find . -type f -iname "*.wav" -ls -exec ditto {} /destination/folder/{} \;

  • find .- Запускает поиск в текущей папке. убедитесь, что вы, cd /source/folderпрежде чем начать

  • -type f - Определяет, чтобы искать только файлы

  • -iname "*.wav" - Это говорит о том, что нужно искать регистр без учета * .wav
  • -ls- Это показывает вам файл, над которым он работает. В противном случае это ничего не показывает.
  • -exec ditto {} /destination/folder/{} \; - выполняет всю работу по копированию и созданию файлов с одинаковым деревом каталогов.

0

Перейдите в каталог:

find . -regex '<regexp_to_get_directories_and_files_you_want>' | xargs -i cp -r --parents {} path/to/destination

Это немного проще и мощнее, если вы управляете регулярными выражениями.


-1

Перейдите в каталог:

cp '*.css' /path/to/destination

Вам придется перейти к каждой папке в каталоге, но это лучше, чем большинство вариантов, которые я видел до сих пор.


Этот метод не является рекурсивным, это означает, что для больших каталогов вы могли бы делать это довольно долго ...
Иан Рид,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.