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

`[!]`(括号中的感叹号)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

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

答案1

引用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括号扩展可用于匹配字符串,但是没有办法(据我所知)对其进行否定。例如

1.{gif,csv,mp3}

扩展为

1.gif 1.csv 1.mp3

无论这些文件是否存在。


作为收费指出shopt可用于启用扩展模式匹配运算符,其中之一是!()。运行后shopt -s extglob,例如

1.!(gif|csv|mp3)

扩展为

1.jpg 1.bmp 1.png

如果这些文件存在于当前目录中。有关详细信息,请阅读man bash(扩展/路径名扩展部分)和路径名扩展(通配符)


对于您要尝试做的事情,我总是会使用find,它提供否定和更多内容,例如以以下方式:

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

这只是列出了调查结果,如果你想删除它们,只需附加-delete选项到最后命令。与删除操作一样:务必先仔细检查

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

答案2

我认为你误解了括号的用法。[abc]匹配字符abc.[!abc]匹配性格不是 a或。b因此c命令

rm myfile [192]

将删除myfile文件19并且2因为 myfile 和括号之间有空格。相比之下,命令

rm myfile[192]

将删除文件myfile1myfile9并且myfile2

答案3

括号[ ]表示字符类。括号内的任何单个字符都可能匹配给定的位置。因此

file[192]

匹配三个可能的名称:

file1
file2
file9

确实如此不是匹配file192,因为它只处理之后的单个字符file

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

!表示否定。

file[!192]

file将匹配在except19或之后包含任何单个字符的文件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" \)

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

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

相关内容