Как использовать команду «cp» для исключения определенного каталога?


411

Я хочу скопировать все файлы в каталоге, кроме некоторых файлов в определенном подкаталоге. Я заметил, что команда 'cp' не имеет опции --exclude. Итак, как мне этого добиться?



6
tar -c | tar -x?
MVDS

1
@mvds, согласен с вами, использование tar с '--exclude' - хорошая идея.
Хуан Ф. Лей

Ответы:


705

rsync быстр и прост:

rsync -av --progress sourcefolder /destinationfolder --exclude thefoldertoexclude

Вы можете использовать --excludeкратные разы.

rsync -av --progress sourcefolder /destinationfolder --exclude thefoldertoexclude --exclude anotherfoldertoexclude

Обратите внимание , что реж thefoldertoexcludeпосле --excludeопции относительно к sourcefolder, т sourcefolder/thefoldertoexclude.

Также вы можете добавить -nпробный запуск, чтобы увидеть, что будет скопировано перед выполнением реальной операции, и, если все в порядке, удалить -nиз командной строки.


3
Согласитесь, вы не можете победить простоту и мощь--exclude
Мэтью Уилкоксон

31
это thefoldertoexcludeотносительный sourcefolderили текущий рабочий каталог? спасибо
Beebee

46
Это относительно исходной папки. Это исключит возможность копирования папки source / .git. rsync -r --exclude '.git' source target
orkoden

15
Может быть, я ошибаюсь, но я считаю хорошей практикой добавлять «переключатели» перед «параметрами». Также man-страница отчетов rsync - исключает возможность использования как с синтаксисом "=", так и без него. Поэтому, чтобы стандартизировать операционные системы, я бы использовал rsync -av --progress --exclude="thefoldertoexclude" sourcefolder /destinationfolder- в любом случае upvote для rsync вместо find, поскольку вы можете легко использовать абсолютные пути для источника, а в find это сложнее, чем {}в dst.
Хави Монтеро

1
@mamun Конечно, например, с удаленного сервера на локальный компьютер: $ rsync user@example.com:/var/www/mypage /var/www/mylocalpage/или с локального на удаленный$ rsync /var/www/mylocalpage/ user@example.com:/var/www/mypage
sobi3ch

84

Что ж, если исключение определенных шаблонов имен файлов должно выполняться каждой файловой утилитой unix-ish (например, cp, mv, rm, tar, rsync, scp, ...), произойдет огромное дублирование усилий. Вместо этого, такие вещи могут быть сделаны как часть подстановка , то есть с помощью вашей оболочки.

удар

man 1 bash, / extglob .

Пример:

$ shopt -s extglob
$ echo images / *
images / 004.bmp images / 033.jpg images / 1276338351183.jpg images / 2252.png
$ echo images /! (*. jpg)
images / 004.bmp images / 2252.png

Таким образом, вы просто помещаете шаблон внутрь !(), и это сводит на нет совпадение. Шаблон может быть сколь угодно сложным, начиная от перечисления отдельных путей (как Ванварил показывает в другом ответе): !(filename1|path2|etc3)до регулярных выражений с звездами и классами персонажей. Обратитесь к странице справки для деталей.

ЗШ

man 1 zshexpn, / генерация имени файла .

Вы можете делать setopt KSH_GLOBи использовать шаблоны, похожие на bash. Или,

% setopt EXTENDED_GLOB
% echo images / *
images / 004.bmp images / 033.jpg images / 1276338351183.jpg images / 2252.png
% echo images / * ~ * .jpg
images / 004.bmp images / 2252.png

Так x~yсоответствует шаблону x, но исключает шаблон y. Еще раз, для полной информации обратитесь к странице man.


рыба новая!

У раковины рыбы есть намного более симпатичный ответ на это:

🐟 cp (строка соответствует -v '* .excluded.names' - srcdir / *) destdir

Бонус pro-tip

Набери cp *, нажми CtrlX*и посмотри что получится. это не вредно, я обещаю


@MikhailGolubtsov, возможно, это потому, что глобализация не является рекурсивной и работает по одному уровню за раз. Отредактировано. PS: это работает, zshхотя.
ulidtko

3
Хороший pro-tip! Таким образом, вы можете легко удалить отдельные элементы. Большое спасибо!
Таффит

Кстати, чтобы отключить расширенные функции сопоставления с образцом в Bash, запустите setopt -u extglob.
Rockallite

49

Зачем использовать, rsyncкогда вы можете сделать:

find . -type f -not -iname '*/not-from-here/*' -exec cp '{}' '/dest/{}' ';'

Это предполагает, что структура целевого каталога совпадает с исходной структурой.


8
Я думаю, что вам нужен -pathаргумент для проверки иерархии путей, а не
Джеймс

3
И вам также понадобится точка с запятой в конце:find . -type f -not -path '*/not-from-here/*' -exec cp '{}' '/dest/{}' \;
Мэтью Уилкоксон

1
Ничего себе, это не позволит мне: "Правки должны быть не менее 6 символов"!
Мэтью Уилкоксон

1
@MatthewWilcoxson Meh. Эти ограничения будут сняты, как только вы получите немного больше повторений. Я отредактировал ответ соответственно. Еще раз спасибо!
Линус Клин

1
@ Хеннинг, почему бы и нет rsync? Ведь это может отсутствовать в системе! в то время как find, cpвсегда на своих местах. Или вы из тех парней, которые установили 2 гига штуки, чтобы делать простые вещи?
Рейшин

37
cp -r `ls -A | grep -v "c"` $HOME/

1
Работал для меня в Windows 10 .sh
atwellpub

Сделана функция оболочки, которая упрощает использование пользовательского исходного пути и # $1 = source path # $2 = destination path # $3 = filter copy_from_source_to_destination_except_filter() { cp -r $(ls -A $1 | grep -v -w $3 | awk -v path=$1 '{printf "%s/%s ", path, $1}') $2 }
исключает

не удается с каталогами с пробелами
Сержио

27

Я нашел самый простой способ, где вы можете скопировать все файлы, кроме файлов и папок, просто добавив их имена в скобках:

shopt -s extglob
cp -r !(Filename1 | FoldernameX | Filename2) Dest/

9
Не работает для меня Я получаю-bash: !: event not found
Geneorama

8
shopt -s extglob (выполните это, чтобы включить! в cp, rm и других)
imkost



8

Rsync

rsync -r --verbose --exclude 'exclude_pattern' ./* /to/where/

и сначала попробуйте это с опцией -n, чтобы увидеть, что будет скопировано


В чем разница / улучшение по сравнению с лучшим ответом?
снижение активности

7

Я предполагаю, что вы используете Bash или Dash. Будет ли это работать?

shopt -s extglob  # sets extended pattern matching options in the bash shell
cp $(ls -laR !(subdir/file1|file2|subdir2/file3)) destination

Выполнение ls, исключая ненужные файлы, и использование этого в качестве первого аргумента для cp


9
Вы можете пропустить лишнее lsи просто сделать cp !(file1|file1) dest.
Шон Чин

Не используйте -laR. это добавляет строку, которая мешает cp. cp $(ls folder/!exclude_folder0|exclude_folder1)) dest
LAL

5

Другой более простой вариант - установить и использовать rsync, который имеет опцию --exclude-dir и может использоваться как для локальных, так и для удаленных файлов.


4

rsyncна самом деле довольно сложно. нужно сделать несколько тестов, чтобы это работало.

Допустим, вы хотите скопировать /var/www/htmlв /var/www/devно необходимости исключить /var/www/html/site/video/ каталог , возможно , из - за его размера. Команда будет:

rsync -av --exclude 'sites/video' /var/www/html/ /var/www/dev

Некоторые оговорки :

  1. Последняя косая черта /в источнике необходима, иначе она также будет копировать исходный каталог, а не его содержимое, и становится/var/www/dev/html/xxxx , что, возможно, не то, что вам нужно.
  2. --excludeПуть по отношению к источнику непосредственно. Даже если вы поставите полный абсолютный путь, он не будет работать.

  3. -vдля подробного, -aдля режима архива, который означает, что вы хотите рекурсию и хотите сохранить почти все.


простое решение, которое заботится о специальных символах и
Сержио

Спасибо за объяснение параметров, в отличие от текущего топ ответа!
снижение активности

3
cp -rv `ls -A | grep -vE "dirToExclude|targetDir"` targetDir

Изменить: забыл исключить целевой путь, а также (в противном случае он будет копировать рекурсивно).


4
Не упустите записи каталога, содержащие пробелы.
Пауло Скардин

3

Это модификация ответа Линуса Клина. Его ответ не работает для меня, потому что будет. добавляется перед путем к файлу, который не нравится cp (путь будет выглядеть как source / .destination / file).

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

find . -type f -not -path '*/exlude-path/*' -exec cp --parents '{}' '/destination/' \;

Команда --parents сохраняет структуру каталогов.



2

Просто переместите его временно в скрытый каталог (и переименуйте его после, если хотите).

mkdir .hiddendir
cp * .hiddendir -R
mv .hiddendir realdirname

1
Возможно, не очень - но это единственный вариант, который я здесь нашел, который работает со cpстандартной оболочкой POSIX sh.
Томекви

1
Этот ответ резко недооценен. Это самый совместимый, самый легкий для чтения и легкий для понимания ответ. Престижность, я не знаю, почему я не думал об этом.
Роберт Талада

Спасибо @RobertTalada, как далеко зайдет ответ? ️‍🌈
lama12345

0

Я использую цикл "do while", чтобы прочитать вывод команды find. В этом примере я сопоставляю (а не исключаю) определенные шаблоны, так как есть более ограниченное число сопоставлений с образцами, которые я хочу, чем те, которые я не хочу. Вы можете изменить логику с -not перед флагами -iname:

    find . -type f -iname "*.flac" -o -print0 -iname "*.mp3" -print0 -o -iname "*.wav" -print0 -o -iname "*.aac" -print0 -o -iname "*.wma" -print0 | while read -d $'\0' file; do cp -ruv "$file" "/media/wd/network_sync/music/$file"; done

Я использую вышеупомянутое, чтобы скопировать все файлы музыкального типа, которые являются более новыми на моем сервере, чем файлы на Live Digital Hub Western Digital TV, которые я смонтировал в / media / wd. Я использую вышеупомянутое, потому что у меня есть много файлов DVD, mpegs и т. Д., Которые я хочу исключить И, потому что по какой-то причине rsync выглядит так, как будто он копирует, но после того, как я посмотрел на устройство wd, файлов там нет, несмотря на отсутствие ошибки во время rsync с этой командой:

    rsync -av --progress --exclude=*.VOB --exclude=*.avi --exclude=*.mkv --exclude=*.ts --exclude=*.mpg --exclude=*.iso --exclude=*ar --exclude=*.vob --exclude=*.BUP --exclude=*.cdi --exclude=*.ISO --exclude=*.shn --exclude=*.MPG --exclude=*.AVI --exclude=*.DAT --exclude=*.img --exclude=*.nrg --exclude=*.cdr --exclude=*.bin --exclude=*.MOV --exclude=*.goutputs* --exclude=*.flv --exclude=*.mov --exclude=*.m2ts --exclude=*.cdg --exclude=*.IFO --exclude=*.asf --exclude=*.ite /media/2TB\ Data/data/music/* /media/wd/network_sync/music/

0
ls -I "filename1" -I "filename2" | xargs cp -rf -t destdir 

Первая часть lsвсех файлов, но скрытые конкретные файлы с флагом -I. Вывод lsиспользуется как стандартный ввод для второй части. xargsпостроить и выполнить команду cp -rf -t destdirиз стандартного ввода. флаг -rозначает рекурсивное копирование каталогов, -fозначает принудительное копирование файлов, которые будут перезаписывать файлы в destdir, -tуказывать конечный каталог для копирования.


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