Відповіді:
У 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*)