`[!]` (знак оклику в дужках) підстановочний знак в башмі


10

Я натрапив на глобальні зразки та шаблони, і мене це особливо цікавить [!].

Ця конструкція схожа на [!]конструкцію, але замість того, щоб відповідати будь-яким символам усередині дужок, вона відповідатиме будь-яким символам, доки вона не вказана між [та ].

rm myfile [!192]

Вище, я вважаю, видалить будь-які / всі файли, за винятком будь-яких / всіх файлів, які мають ім'я 192.

Однак мене турбує правильне використання цього файлу з розширенням файлу, зокрема, з кількома умовами.

Який би був правильний синтаксис у такій ситуації?

rm myfile [!.gif .csv. mp3] 

або

rm myfile [!.gif !.csv !.mp3]

Мене хвилює те, що період може бути заміщений, і тому будь-який файл із .(який би був будь-який із них?) Потім маніпулював би, коли я прагну викликати маніпуляції з певними файлами.

Ця конструкція схожа на [ ]конструкцію, але замість того, щоб відповідати будь-яким символам усередині дужок, вона відповідатиме будь-яким символам, доки вона не вказана між [та ].

(цитується з http://www.tldp.org/LDP/GNU-Linux-Tools-Summary/html/x11655.htm )

Тепер; мені здається, що однини !є достатньою, і всі значення в ній після містяться в межах.


5
як загальну пораду, перед тим, як запустити , скористайтеся ls my-patternабо echo my-commandперевірте, чи робиться rm
глобус

Також пам’ятайте, що багато, якщо не більшість файлів не мають розширень. Розширення в системах Linux зазвичай не мають значення і не використовуються для визначення типу файлу більшістю програм.
тердон

2
Зауважте, що ваша перша цитата неправильно цитується, але тепер, здається, в основному це [!]говорить схоже, але не так[!]
ilkkachu

2
Варто згадати, що ^має таке саме значення, як і !в цьому контексті, тому [^a]виключає aточно так само, як [!a]це робиться: Якщо перший символ, що слідує за [є a! або ^, тоді будь-який символ, що не вкладається, відповідає. ( man bash)
десерт

3
rm myfile [!192]видалить myfileбудь-який файл Односимвольний, а не по імені 1, 9або 2.
Кевін

Відповіді:


16

Цитуючи man 7 glob:

An  expression  "[!...]"  matches  a single character, namely any character
that is not matched by the expression obtained by removing the first '!' from it.
(Thus, "[!]a-]" matches any single character except ']', 'a' and '-'.)

Наголос на окремій символьній частині тут []не можна використовувати для цілих рядків у Bash Pattern Matching.


bash«S Скоба розширення може бути використано для зіставлення рядків, однак немає ніякого способу (я знаю) , щоб заперечувати їх. Напр

1.{gif,csv,mp3}

розширено до

1.gif 1.csv 1.mp3

незалежно від того, існують ці файли.


Як зазначається wchargin , shoptможна використовувати для включення операторів розширеного узгодження шаблонів, одним з яких є !(). Після бігу shopt -s extglob, наприклад

1.!(gif|csv|mp3)

розширено до

1.jpg 1.bmp 1.png

якщо ці файли існують у поточному каталозі. Детальніше man bash(розділ Розширення / Розширення імені Pathname) та Розширення Pathname (глобальний) .


Для того, що ви намагаєтесь зробити, я завжди використовував find, що пропонує заперечення та багато іншого, наприклад таким чином:

find . -maxdepth 1 -type f ! -name "*.gif" -a ! -name "*.csv" -a ! -name "*.mp3"

Тут просто перераховані результати, якщо ви хочете їх видалити, просто додайте -deleteпараметр до кінця команди. Як завжди з видаленням дій: Завжди завжди ретельно перевіряйте .

findпропонує багато корисних варіантів, дуже добре пояснених man find.


1
Зауважте, що ця findкоманда є рекурсивною ( редагуйте: як було показано спочатку - я можу зберегти цей коментар для додаткової відповідної, але несуттєвої інформації, яку він передає). Щоб знайти файли, що знаходяться лише в поточному каталозі, але не також їх підкаталогах - і таким чином видалити ці файли лише у випадку, якщо -deleteдія буде додано - ви можете додати їх -maxdepth 1відразу після find .. Це приведе це у відповідність до ефекту глобулінгу, оскільки глобуси нерекурсивні в Bash, якщо тільки параметр globstarоболонки не ввімкнено та **не використовується. Глобус, показаний у питанні, нерецидивний у всіх оболонках.
Елія Каган

2
«Немає ніякого способу (я знаю) , щоб звести на ні їх» -з shopt -s extglob, ви можете використовувати echo 1.!(gif|csv|mp3), який друкує все , 1.extде extнемає gif, csvабо mp3. (Див. Підрозділ " man bash
Збірка

10

Я думаю, ви неправильно зрозуміли використання дужок. [abc]відповідає одному з символів a, bабо c. [!abc]відповідає одному символу, якого немає a , bабо c. Тож заповідь

rm myfile [192]

видалить myfileі файли 1, 9і 2тому, що у вас є проміжок між myfile та дужкою. На відміну від команди

rm myfile[192]

видалить файли myfile1, myfile9і myfile2.


правда. Краще використовувати find.
pLumo

Насправді [] використовується для діапазону, [!] Один символ
IronUhlan

1
@IronUhlan, вони обидва приймають діапазон або список символів. Просто інше - це заперечення.
ilkkachu

7

Дужки [ ]позначають клас символів. Будь-який окремий символ всередині них може відповідати заданій позиції. Тому

file[192]

відповідає трьом можливим іменам:

file1
file2
file9

Це не відповідає file192, оскільки займається лише одним символом після file.

Ми також можемо використовувати діапазони в дужках. [0-9]відповідає будь-якій одній цифрі в даній позиції. Для двох цифр нам потрібно [0-9][0-9]. Для цифри з великої літери ми можемо використовувати [0-9][A-Z]...

! вказує на заперечення.

file[!192]

відповідатиме файлам, які мають будь-який єдиний символ після fileвинятку 1або 9або 2. Наприклад, він буде відповідати file7і filesі file%(та багатьом іншим), але ні file192 , тому що в ньому є два зайвих символи.

Для вашого випадку використання я пропоную використовувати findзамість цього [!]. Він має notоператора.

Він також рекурсивний , а значить, за замовчуванням він переходить у всі підкаталоги. Ви можете обмежити його поточним каталогом -maxdepth 1, якщо це те, що ви хочете. Підстановочні символи оболонок (глобулінг) не є рекурсивними (хоча рекурсивне глобулювання за допомогою **можна включити).

Припускаючи, що ви не хочете уникати видалення символьних посилань, ми можемо додати -type dдо заперечних тестів, щоб уникнути видалення каталогів. Дякую Елію Каган за цю пропозицію.

find /path -maxdepth 1 -not \( -type d -or -iname "*.gif" -or -iname "*.csv" -or -iname "*.mp3" \)

Якщо ви бачите, що ви хочете, можете знову запустити команду -delete

find /path -maxdepth 1  -not \( -type d -or -iname "*.gif" -or -iname "*.csv" -or -iname "*.mp3" \) -delete

2
І я думаю, ви також можете зробити відразу кілька діапазонів. Наприклад, шістнадцяткова цифра могла бути[0-9a-fA-F]
Вілсон

@Zanna, так! Я фактично використовував find :) Не зрозумів, що у нього оператор "не" :)
IronUhlan
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.