Відповіді:
У Bash ви можете зробити це, включивши extglobопцію, як це (замінити lsз cpі додати цільової каталог, звичайно)
~/foobar> shopt extglob
extglob off
~/foobar> ls
abar afoo bbar bfoo
~/foobar> ls !(b*)
-bash: !: event not found
~/foobar> shopt -s extglob # Enables extglob
~/foobar> ls !(b*)
abar afoo
~/foobar> ls !(a*)
bbar bfoo
~/foobar> ls !(*foo)
abar bbar
Пізніше ви можете відключити extglob за допомогою
shopt -u extglob
f, крім foo?
Параметр extglobоболонки дає більш потужне узгодження шаблону в командному рядку.
Ви вмикаєте його shopt -s extglobі вимикаєте shopt -u extglob.
У вашому прикладі ви б спочатку робили:
$ shopt -s extglob
$ cp !(*Music*) /target_directory
Повний доступний внутр закінчився GLOB оператори Бінг є (витяг з man bash):
Якщо параметр оболонки extglob увімкнено за допомогою вбудованого магазину, розпізнається кілька розширених операторів відповідності шаблону. Список шаблонів - це список одного або декількох шаблонів, розділених знаком |. Складені візерунки можуть бути сформовані з використанням одного або декількох з наступних підшаблонів:
- ? (шаблон-список)
Відповідає нулю або одному зустрічанню заданих шаблонів- * (список шаблонів)
Відповідає нулю або більше входжень заданих шаблонів- + (перелік шаблонів)
Збігає одне або більше входжень заданих шаблонів- @ (список шаблонів)
Відповідає одному із заданих шаблонів- ! (список шаблонів)
Відповідає будь-якому, крім однієї із заданих шаблонів
Так, наприклад, якщо ви хочете перерахувати всі файли в поточному каталозі, які не є, .cабо .hфайли, ви зробите:
$ ls -d !(*@(.c|.h))
Звичайно, нормальне обшивання оболонки працює, тому останній приклад також можна записати як:
$ ls -d !(*.[ch])
.cабо .h- це каталог.
D, але не вміст підкаталогів, які можуть міститися в каталозі D.
Не в баші (що я знаю), але:
cp `ls | grep -v Music` /target_directory
Я знаю, що це не саме те, що ви шукали, але це вирішить ваш приклад.
Якщо ви хочете уникнути вартості пам’яті за допомогою команди exec, я вважаю, що ви можете зробити краще з xargs. Я думаю, що наступне є більш ефективною альтернативою
find foo -type f ! -name '*Music*' -exec cp {} bar \; # new proc for each exec
find . -maxdepth 1 -name '*Music*' -prune -o -print0 | xargs -0 -i cp {} dest/
У bash альтернативою shopt -s extglobє GLOBIGNOREзмінна . Насправді не краще, але мені легше запам'ятати.
Приклад, який може бути тим, що хотів оригінальний плакат:
GLOBIGNORE="*techno*"; cp *Music* /only_good_music/
Закінчивши, unset GLOBIGNOREмати змогу rm *techno*у вихідному каталозі.
Ви також можете використовувати досить простий forцикл:
for f in `find . -not -name "*Music*"`
do
cp $f /target/dir
done
-maxdepth 1для нерекурсивного?
findзадніх посилань порушить неприємні способи, якщо він знайде будь-які нетривіальні імена файлів.
Мої особисті переваги - використовувати grep та команду while. Це дозволяє писати потужні, але читабельні сценарії, що гарантує вам, що ви робите саме те, що хочете. Крім того, використовуючи команду echo, ви можете виконати сухий запуск перед виконанням фактичної операції. Наприклад:
ls | grep -v "Music" | while read filename
do
echo $filename
done
буде надрукувати файли, які ви закінчите копіювати. Якщо список правильний, наступним кроком буде просто замінити команду echo командою copy, як описано нижче:
ls | grep -v "Music" | while read filename
do
cp "$filename" /target_directory
done
bashви можете використовувати while IFS='' read -r filename, але тоді нові рядки по - , як і раніше є проблемою. Взагалі найкраще не використовувати lsдля перерахування файлів; такі інструменти findнабагато краще підходять.
for file in *; do case ${file} in (*Music*) ;; (*) cp "${file}" /target_directory ; echo ;; esac; done
Трюк я не бачив тут ще , що не використовується extglob, findабо grepє для лікування двох списків файлів як наборів та «диф» їх з допомогою comm:
comm -23 <(ls) <(ls *Music*)
commє кращим над diffтим, що він не має зайвої крихти.
Це повертає всі елементи множини 1 ls, які також не є у множині 2 ls *Music*,. Для коректної роботи обидва набори мають бути відсортовані. Немає проблем для lsглобального розширення, але якщо ви використовуєте щось подібне find, не забудьте звернутися до цього sort.
comm -23 <(find . | sort) <(find . | grep -i '.jpg' | sort)
Потенційно корисно.
comm -23 <(ls) exclude_these.list
Одне рішення для цього можна знайти із знахідкою.
$ mkdir foo bar
$ touch foo/a.txt foo/Music.txt
$ find foo -type f ! -name '*Music*' -exec cp {} bar \;
$ ls bar
a.txt
У Find є досить багато варіантів, ви можете отримати досить конкретний характер того, що ви включаєте та виключаєте.
Редагувати: Адам у коментарях зазначив, що це рекурсивно. знайти варіанти mindepth та maxdepth можуть бути корисними для управління цим.
find -maxdepth 1 -not -name '*Music*'/ target_directory
У наступних роботах перераховані всі *.txtфайли в поточному режимі, крім тих, що починаються з числа.
Це працює bash, dash, zshі всі інші POSIX сумісних оболонок.
for FILE in /some/dir/*.txt; do # for each *.txt file
case "${FILE##*/}" in # if file basename...
[0-9]*) continue ;; # starts with digit: skip
esac
## otherwise, do stuff with $FILE here
done
У першому рядку візерунок /some/dir/*.txtспричинить forциклічне повторення всіх файлів, на /some/dirім'я яких закінчується .txt.
У другому рядку випадок справи використовується для вилучення небажаних файлів. - ${FILE##*/}Вираз знімає будь-який провідний компонент імені dir з імені файлу (тут /some/dir/), щоб малюнки могли співставити лише базове ім'я файлу. (Якщо ви відмиваєте лише назви файлів на основі суфіксів, можете скоротити це $FILEзамість цього.)
У третьому рядку всі файли, що відповідають caseшаблону [0-9]*) будуть пропущені ( continueоператор переходить до наступної ітерації forциклу). - Якщо ви хочете, ви можете зробити щось більш цікаве тут, наприклад, пропустити всі файли, які не починаються з букви (a – z) [!a-z]*, або ви можете використовувати кілька шаблонів, щоб пропустити декілька типів імен файлів, наприклад, [0-9]*|*.bakщоб пропустити файли обох .bakфайлів , і файли, які не починаються з числа.
*.txtзамість просто *). Виправлено зараз.
це зробить це, виключаючи саме "Музику"
cp -a ^'Music' /target
це та інше для виключення таких речей, як Музика? * чи *? Музика
cp -a ^\*?'complete' /target
cp -a ^'complete'?\* /target
cpкерівництва на MacOS має -aможливість, але вона робить щось зовсім інше. Яка платформа це підтримує?
ls /dir/*/!(base*)