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

71

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

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

unclaimedbaggage
источник
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/{} \;
sborsky
источник
Вы пропустили .после 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
icyerasor
источник
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

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

keywalker
источник
-1

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

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

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

Феникс
источник
Этот метод не является рекурсивным, это означает, что для больших каталогов вы могли бы делать это довольно долго ...
Иан Рид,