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 )

现在; 对我来说,这意味着一个单数! 足够,其后的所有值都包含在该范围内。

引用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模式匹配中的整个字符串。


bash的Brace Expansion可用于匹配字符串,但是(我知道)没有办法否定它们。 例如

 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)和路径名扩展(globbing) 。


对于你想要做的事情,我总是使用find ,它提供了否定等等,例如以下列方式:

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

这只列出了结果,如果要删除它们,只需将-delete选项附加命令的末尾即可 。 与删除操作一如既往:请务必先仔细检查

find提供了大量有用的选项,由man find很好地解释。

我认为你误解了括号的使用。 [abc]匹配字符abc[!abc]匹配一个 不是 abc字符。 所以这个命令

 rm myfile [192] 

将删除myfile和文件92因为myfile和括号之间有空格。 相反,命令

 rm myfile[192] 

将删除文件myfile1myfile9myfile2

Brackets [ ]表示一个字符类。 其中的任何单个字符都可以在给定位置匹配。 所以

 file[192] 

匹配三个可能的名称:

 file1 file2 file9 

它与file192 匹配,因为它只处理file后的单个字符。

我们也可以在括号中使用范围。 [0-9]匹配给定位置中的任何一位数。 对于两位数,我们需要[0-9][0-9] 。 对于后跟大写字母的数字,我们可以使用[0-9][AZ]

! 表示否定。

 file[!192] 

将匹配文件后除192之外的任何单个字符的file 。 例如,它将匹配file7filesfile% (和许多其他)但 file192 ,因为它有两个额外的字符。

对于您的用例,我建议使用find而不是[!] 。 它有一个not运算符。

它也是递归的 ,这意味着它默认进入所有子目录。 您可以使用-maxdepth 1将其限制在当前目录中,如果这是您想要的。 Shell通配符(globbing)是非递归的(虽然可以启用带**递归通配)。

假设您不想避免删除符号链接,我们可以将-type d添加到否定测试中以避免删除任何目录。 感谢Eliah Kagan的建议。

 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