“ (восклицательный знак в скобках) подстановочный знак в bash

Я натолкнулся на шаблоны глобусов и подстановочные знаки и представляю для меня особый интерес [!] .

Эта конструкция похожа на конструкцию [!] , Но вместо сопоставления любых символов внутри скобок она будет соответствовать любому символу, если она не указана между [ и ] .

 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 )

Теперь; для меня, что предлагает тогда единственное ! является достаточным, и все значения в нем после этого содержатся в пределах диапазона.

Citing 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.


Расширение Brace расширения bash может использоваться для сопоставления строк, однако нет способа (я знаю), чтобы отрицать их. Например

 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 (раздел EXPANSION / Pathname Expansion) и расширение Pathname (globbing) .


Для того, что вы пытаетесь сделать, я всегда буду использовать find , который предлагает отрицание и многое другое, например, следующим образом:

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

Это просто показывает результаты, если вы хотите их удалить, просто добавьте параметр -delete в конец команды. Как всегда с удалением действий: Всегда проверяйте сначала .

find предложения тонны полезных опций, очень хорошо объясняемых man find .

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

 rm myfile [192] 

удалит myfile и файлы 1 , 9 и 2 потому что у вас есть пробел между myfile и скобкой. Напротив, команда

 rm myfile[192] 

удалит файлы myfile1 , myfile9 и myfile2 .

Скобки [ ] обозначают класс символов. Любой отдельный символ внутри них может совпадать в данной позиции. Так

 file[192] 

соответствует трем возможным именам:

 file1 file2 file9 

Он не соответствует file192 , поскольку он имеет дело только с одиночным символом после file .

Мы также можем использовать диапазоны в скобках. [0-9] соответствует любой отдельной цифре в данной позиции. Для двух цифр нам нужно [0-9][0-9] . Для цифры, за которой следует заглавная буква, мы можем использовать [0-9][AZ]

! указывает на отрицание.

 file[!192] 

будут соответствовать файлам, у которых есть один символ после file кроме 1 или 9 или 2 . Например, он будет соответствовать file7 и files и file% (и многим другим), но не file192 , потому что у него есть два дополнительных символа.

Для вашего случая использования я предлагаю использовать find вместо [!] . У него not оператора.

Он также рекурсивный , что означает, что он по умолчанию входит во все подкаталоги. Вы можете ограничить его текущим каталогом с помощью -maxdepth 1 , если это то, что вы хотите. Символы оболочки (globbing) не являются рекурсивными (хотя рекурсивное переключение с ** может быть включено).

Предполагая, что вы не хотите избегать удаления символических ссылок, мы можем добавить -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