У меня есть папка с большим количеством файлов. Я хочу скопировать все файлы, которые начинаются с этих имен (разделенных пробелом):
abc abd aer ab-x ate
в другую папку. Как это сделать?
решение1
С csh
, tcsh
, ksh93
, bash
, fish
или zsh -o cshnullglob
, вы можете использоватьрасширение скобкииподстановкачтобы сделать это ( --
для этих имен файлов это не требуется, но я предполагаю, что это просто примеры):
cp -- {abc,abd,aer,ab-x,ate}* dest/
Если вы не хотите использовать раскрытие фигурных скобок, можно использовать цикл for (здесь синтаксис в стиле POSIX/Bourne):
for include in abc abd aer ab-x ate; do
cp -- "$include"* dest/
done
Если у вас очень большое количество файлов, это может быть медленно из-за вызова cp
один раз на включение. Другой способ сделать это — заполнить массив и идти оттуда (здесь ksh93
или zsh
недавний bash
синтаксис):
files=()
includes=(abc abd aer ab-x ate)
for include in "${includes[@]}"; do
files+=( "$include"* )
done
cp -- "${files[@]}" dest/
решение2
Примечание о расширении скобок и подстановке.
Расширение скобок не является подстановкой (хотя в csh/tcsh, где оно возникло, это различие не столь очевидно, как в других оболочках). Оно выполняетсядоподстановка.
Итак, когда вы это сделаете:
cp {a,b}* /dest
Сначала он расширяется до:
cp a* b* /dest
Это означает, что оболочке придется развернуть два глобуса, то есть дважды получить полный список файлов и дважды посмотреть, какие из них соответствуют шаблону.
При использовании zsh
, это также означает, что если какой-либо глобальный массив не соответствует ни одному файлу, вся команда отменяется (эту проблему можно обойти, включив опцию, cshnullglob
ведущую себя как в csh).
Это также означает, что если у вас есть
cp {a,ab}* /dest
cp
скопирует ab*
файлы дважды.
Это отличается от:
cp @(a|b)* /dest
или ksh
или bash -O extglob
, zsh -o kshglob
или
cp (a|b)* /dest
из zsh
. Там, это толькоодинglob, поэтому это будет более эффективно, и файлы будут включены только один раз.
С помощью zsh
, если у вас есть список префиксов в массиве:
prefixes=(abc abd aer ab-x ate)
cp -- (${(j:|:)~prefixes})* /dest
(выше префиксы рассматриваются как глоб). То есть объединяем элементы массивов |
и рассматриваем результат как глоб ( ~
).
Если список большой, вы можете обнаружить, что выполнение cp
завершается ошибкой"список аргументов слишком длинный"ошибка. В этом случае вы можете использовать zsh
встроенную версию, cp
которую вы можете загрузить, загрузив zsh/files
модуль ( zmodload zsh/files
).
решение3
Например, у меня в текущем каталоге есть следующие файлы:
1-s2.0-S0038092X0000058X-main.pdf ANNDHW.pdf HPcalculation2 1-s2.0-S0306261999000422-main.pdf ANNlee.pdf HPcalculation3 ANNCanada.pdf HPcalculation HPcalculation4
Я хочу переместить все файлы, начиная с HP, в папку:
./NewFolder/
Я могу сделать:
cp ./HP* ./NewFolder/
./HP*
скажет linux, что меня интересуют все файлы, начинающиеся с HP. Обратное — когда меня интересуют все файлы, заканчивающиеся на.pdf
. Я могу поставить*
перед.pdf
:cp ./*.pdf ./NewFolder/
решение4
Просто вы можете сделать
cp abc* abd* aer* ab-x* ate* DestinationPath
Решение вашей расширенной проблемы может быть
- поместить все имена файлов в список, например list0.txt
Копировать все с
cp `cat list0.txt` DestinationPath # Не нужно пробелов в именах файлов
или лучше,
while read -r file; do cp "$file" dest/ ; done < list0.txt
Примечания:
- "$file", потому что так вы можете обрабатывать имя с пробелами внутри, как
One Package.deb
-r
это защитит вас от побегов.-r Обратная косая черта не действует как экранирующий символ. Обратная косая черта считается частью строки. В частности, пара обратная косая черта-новая строка не может использоваться как продолжение строки