Как скопировать некоторые, но не все файлы?

54

Таким образом, вы можете использовать в *качестве подстановочного знака для всех файлов при использовании cpв контексте каталога. Есть ли способ скопировать все файлы, кроме xфайла?

Чад Харрисон
источник

Ответы:

42

В bashвы можете использовать extglob:

 $ shopt -s extglob  # to enable extglob
 $ cp !(b*) new_dir/

где !(b*)исключить все b*файлы.

Вы можете позже отключить extglobс помощью

 $ shopt -u extglob
порыв
источник
Вы знаете, есть ли что-то эквивалентное для оболочки tcsh?
Левон
К сожалению, нет. Похоже, findэто единственный путь tcsh:find . -maxdepth 1 ! -name "exclude*" -exec cp -t destination {} \+
спешить
50

Rsync прекрасно с этим справляется.

Пример скопировать все: rsync -aP /folder1/* /folder/2

Пример копирования всех с исключением: rsync -aP --exclude=x /folder1/* /folder2/

-aPПереключатель:

a: аналогично cp -a, рекурсивный и т. д. P: показывает прогресс, хорошая функция rsync.

Тим
источник
5
И посмотрите этот ответ для краткого руководства по общим спискам исключений rsync.
Жиль "ТАК - перестань быть злым"
1
На darwin / MacOS, используйте -rPвместо, -aPесли хотите рекурсировать. -aдля архивирования. Не уверен, изменилось ли это или просто изменилось в MacOS.
jpoveda
rsyncдействительно есть возможность сделать его рекурсивным. Пример: rsync --recursive -P --exclude=x /folder1/* /folder2/. (Проверено только в Ubuntu)
n1k31t4
12

Это не особенность cp, это особенность вашей оболочки (она расширяет *для обозначения всех файлов без точек), поэтому ответ зависит от того, какую оболочку вы используете. Например, zshподдерживает этот синтаксис:

$ cp ^x /path/to/destination

Где ^xозначает "все файлы, кроме x"

Вы также можете комбинировать шаблоны выбора и отмены выбора, например, чтобы скопировать все файлы wav, кроме тех, которые содержат xyz, вы можете использовать:

cp *.wav~*xyz*
Михаил Мрозек
источник
Есть комментарии bash?
Чад Харрисон
@hydroparadise Я не знаю много о Bash, но этот ответ, кажется, покрывает его
Майкл Мрозек
Что насчет tcsh? Кто-нибудь знает?
Левон
4

Может также быть выполнено в простой старой (переносной / совместимой) оболочке Bourne различными способами со стандартными инструментами гораздо менее изящными способами, чем использование расширенного сглаживания оболочки или команд со встроенными опциями исключения.

Если файлов не слишком много (и не с именами, включая пробелы и / или разрывы строк), это может быть способом:

cp `ls | egrep -v '^excludename$'` destdir/.

Конечно, bashи инструменты GNU великолепны и мощны, но они все еще не всегда доступны. Если вы собираетесь поместить его в переносимый скрипт, я бы порекомендовал findкак в комментарии Rush.

MattBianco
источник
2
Я считаю, что последняя часть вашего ответа просто отвлекает от темы под рукой. Кроме того, «Unix» больше не является золотым стандартом (если он когда-либо был). Просто не имеет значения, является ли что-то «Unix» или нет, несмотря на то, что название этого сайта - «Unix и Linux».
Александр
2
ХОРОШО. Вместо этого я переместил комментарий сюда: Unix не является GNU. Я согласен с тем, что «единство» вещей не очень интересно, но я все еще верю в мобильность и немного знаю о вашей истории.
MattBianco
Полностью с тобой согласен.
Александр
2

Если вы хотите скопировать все в папке (включая подпапки) в определенный подкаталог:

cp -R $(ls | grep -v '^subdir$') subdir/

Работает с sh, bash, zsh (как минимум).

user2707671
источник
1
Убедите меня, что это не то же самое намерение, что иcp -R * subdir/
roaima
1
Если вы используете эту команду «cp -R * subdir /», bash / zsh попытался скопировать «subdir» рекурсивно. В результате вы получите ошибку: «имя слишком длинное (не скопировано)».
user2707671
Хорошая точка зрения. Ваше предложение пытается избежать предупреждения от cp(не от bash/ sh), " cp: cannot copy a directory, ‘subdir’, into itself, ‘subdir/subdir’". Копия завершается правильно, хотя. К сожалению, ваш вариант ломается с любым именем файла, содержащим пробел или пунктуацию, чувствительную к оболочке. См. Unix.stackexchange.com/q/128985/135943
роайма
-1

extglob Я думаю, это лучший способ.

Другой способ использования cp $(ls --ignore=x) subdir/

Эдвин Ли
источник
Это сломается при любой форме специальных символов в именах файлов. (Пробелы, переводы строки $и т. Д.) Никогда не анализируйте выходные данные ls. unix.stackexchange.com/q/128985/135943
подстановочный