`[!]`(括号中的感叹号)bash 中的通配符

Jac*_*ite 10 command-line bash

我遇到了通配符模式和通配符,我特别感兴趣的是[!].

此构造与 构造类似[!],不同之处在于它不匹配括号内的任何字符,而是匹配任何字符,只要它不在[和之间列出]

rm myfile [!192]
Run Code Online (Sandbox Code Playgroud)

我相信以上内容将删除任何/所有文件,但名称中包含 192 的任何/所有文件除外。

然而,我担心在文件扩展名中正确使用它,尤其是在多个条件下。

在这种情况下,正确的语法是什么?

rm myfile [!.gif .csv. mp3] 
Run Code Online (Sandbox Code Playgroud)

或者

rm myfile [!.gif !.csv !.mp3]
Run Code Online (Sandbox Code Playgroud)

我担心句号可能放错了位置,因此当我试图对特定文件进行操作时,任何带有 a .(肯定是其中任何一个?)的文件都会被操作。

此构造与 构造类似[ ],不同之处在于它不匹配括号内的任何字符,而是匹配任何字符,只要它不在[和之间列出]

(引自http://www.tldp.org/LDP/GNU-Linux-Tools-Summary/html/x11655.htm

现在; 对我来说,这表明单数!就足够了,之后的所有值都包含在该范围内。

des*_*ert 17

引用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 '-'.)
Run Code Online (Sandbox Code Playgroud)

这里强调单字符部分,[]不能用于 Bash 模式匹配中的整个字符串。


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

1.{gif,csv,mp3}
Run Code Online (Sandbox Code Playgroud)

扩展为

1.gif 1.csv 1.mp3
Run Code Online (Sandbox Code Playgroud)

不管这些文件是否存在。


正如wchargin 所指出的,shopt可用于启用扩展模式匹配运算符,其中之一是!(). 运行后shopt -s extglob,例如

1.!(gif|csv|mp3)
Run Code Online (Sandbox Code Playgroud)

扩展为

1.jpg 1.bmp 1.png
Run Code Online (Sandbox Code Playgroud)

如果这些文件存在于当前目录中。更多阅读man bash(扩展/路径名扩展部分)和路径名扩展(通配)


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

find . -maxdepth 1 -type f ! -name "*.gif" -a ! -name "*.csv" -a ! -name "*.mp3"
Run Code Online (Sandbox Code Playgroud)

这只是列出了结果,如果你想删除它们,只需将-delete选项附加命令的末尾。与删除操作一样:始终首先仔细检查

find提供了大量有用的选项,由man find.


pLu*_*umo 10

我认为您误解了括号的使用。[abc]匹配一个字符abc[!abc]匹配一个不是 a,b或 的字符c。所以命令

rm myfile [192]
Run Code Online (Sandbox Code Playgroud)

将删除myfile和文件19而且2因为你有Myfile和支架之间的空间。相比之下,命令

rm myfile[192]
Run Code Online (Sandbox Code Playgroud)

将删除文件myfile1myfile9myfile2.


Zan*_*nna 7

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

file[192]
Run Code Online (Sandbox Code Playgroud)

匹配三个可能的名称:

file1
file2
file9
Run Code Online (Sandbox Code Playgroud)

匹配file192,因为它只有在对单字符交易file

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

! 表示否定。

file[!192]
Run Code Online (Sandbox Code Playgroud)

将匹配在fileexcept19或之后具有任何单个字符的文件2。例如,它将匹配file7andfilesfile%(以及许多其他的)但 匹配file192,因为它有两个额外的字符。

对于您的用例,我建议使用find而不是[!]. 它有一个not操作员。

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

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

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

如果你看到你想要的,你可以再次运行命令 -delete

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

  • 而且我认为你也可以一次做几个范围。例如,十六进制数字可以是`[0-9a-fA-F]` (2认同)