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


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-patternecho my-command检查是否按照所需的方式完成了rm
遍历

另外,请记住,即使不是大多数,很多文件都没有扩展名。Linux系统上的扩展名通常无关紧要,大多数程序都不使用扩展名来定义文件类型。
terdon

2
请注意,您的第一个报价被错误引用,现在看来基本上是说[!]相似但不相似[!]
ilkkachu

2
值得一提的是,它的^含义与此处的含义完全相同!,因此,它的[^a]排除与之a完全相同[!a]如果[之后的第一个字符是!!或^,则匹配所有未包含的字符。man bash
甜点

3
rm myfile [!192]将删除myfile,以及任何单个字符的文件没有命名192
凯文

Answers:


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中的整个字符串。


bashBrace 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(请参见“ 扩展/路径名扩展”和“ 路径名扩展”)


对于您要尝试执行的操作,我将始终使用find,它提供了否定的功能,例如,通过以下方式:

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

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

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


1
请注意,此find命令是递归的(编辑:如其最初所示 -我可能会保留此注释以获取它传达的其他相关但非必需的信息)。要查找仅位于当前目录中而不位于其子目录中的文件(因此,如果-delete添加了操作,则仅删除这些文件)可以在-maxdepth 1之后添加find .。这将使其与globbing的效果保持一致,因为glob在Bash中是非递归的,除非globstar打开并**使用了shell选项。问题中显示的glob在所有shell中都是非递归的。
伊莱亚·卡根

2
“没有办法(我知道)来否定他们” -附shopt -s extglob,你可以使用echo 1.!(gif|csv|mp3),打印所有的1.ext地方ext不是gifcsvmp3。(请参阅的“模式匹配”小节man bash。)
wchargin

10

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

rm myfile [192]

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

rm myfile[192]

将删除文件myfile1myfile9并且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]

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

对于您的用例,建议使用find代替[!]。它有一个not运算符。

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

假设您不想避免删除符号链接,我们可以添加-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

2
而且我认为您也可以一次进行多个范围调整。例如,十六进制数字可能是[0-9a-fA-F]
Wilson

@Zanna,是的!我实际上是在使用find :)没意识到它有一个“ not”运算符:)
IronUhlan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.