a[bc]d
和 和有什么区别a{b,c}d
?a{b,c}d
既然已经有了,为什么人们还要使用呢a[bc]d
?
答案1
两者截然不同。
a[bc]d
是一个文件名模式(在除 之外的外壳中fish
)。它将扩展到两个文件名 abd
如果acd
这些是当前目录中现有文件的名称。
该
[...]
部分是一个括号表达式,匹配列出的字符中的单个字符(或在包含范围时对元素进行整理)。要匹配模式a[bc]d
,字符串之间a
和d
文件名中的字符必须是 ab
或 ac
。如果
abd
存在但acd
不存在,则它只会扩展为abd
,反之亦然。如果 、
abd
也不acd
存在,根据 shell 和选项,它将触发错误(原始 Unixsh
、(t)csh
、zsh
、fish
、bash -O failglob
),并可能退出 shell,或保留模式未展开(类似于 Bourne 和rc
类似 shell)或展开到什么都没有(bash/zsh/yash -o nullglob
、一些旧版本的fish
、原始 Unixsh
以及(t)csh
同一命令中是否有其他匹配的 glob )。
a{b,c}d
是一个大括号扩展(在支持这些的 shell 中)。它将扩展到两个字符串 abd
和acd
。
该
{...}
部分是一组以逗号分隔的字符串(在本例中;在某些 shell 中,它也可能是一个范围,例如a..k
or20..25
或更高级的范围,例如00..20..2
or0..20..2%02d
),并且通过将这些字符串中的每一个与侧翼组合来计算扩展字符串a
和d
.这些字符串可能比单个字符长,也可能是大括号扩展本身。无论这些字符串是否对应于现有文件名,都会发生扩展。
如果要构造字符串,请使用大括号扩展。如果要匹配文件名,请使用文件名模式。
1 在这种特殊情况下,a[bc]d
可能恰好是现有文件的名称,这就是为什么rm -f ./*.[ch]
在这些 shell 中使用类似的东西有潜在危险并且rm -f ./*.{c,h}
问题不大。
答案2
a[bc]d
是模式匹配,并且是 POSIX 标准的一部分。在 POSIX 中,这被称为“模式括号表达式”。它记录在手册第 2.13 节
当不加引号且位于括号表达式之外时,以下三个字符在模式规范中应具有特殊含义:
?
问号是一种与任何字符匹配的模式。
*星号是一种匹配多个字符的模式,如匹配多个字符的模式中所述。
[开括号应引入模式括号表达式。
第 2.13.3 节还提到,当它用于文件名扩展时,它的行为与通常的正则表达式的预期不同(我强调)
到目前为止在匹配单个字符的模式和匹配多个字符的模式中描述的规则由以下规则限定,当模式匹配表示法用于文件名扩展时,这些规则适用:
路径名中的斜杠字符应通过在模式中使用一个或多个斜杠来显式匹配;它既不能与星号或问号特殊字符匹配,也不能与方括号表达式匹配。模式中的斜杠应在括号表达式之前识别;因此,斜杠不能包含在用于文件名扩展的模式括号表达式中。如果在找到相应的右方括号之前在未转义的左方括号字符后面发现斜杠字符,则该左方括号应被视为普通字符。例如,该模式 与或
"a[b/c]d"
等路径名不匹配。它只匹配字面上的路径名。abd
a/d
a[b/c]d
a{b,c}d
是大括号扩张,它不在 POSIX 的规范中。这是 bash 中的相应部分手动的(我强调的):
大括号扩展是一种机制,通过该机制可以任意字符串可能会产生。这个机制类似于文件名扩展(请参阅文件名扩展),但是生成的文件名不必存在。要展开大括号的模式采用可选的形式前言, 后跟一系列逗号分隔的字符串或一对大括号之间的序列表达式,后跟可选的 后记。前导码作为大括号内包含的每个字符串的前缀,然后将附言附加到每个结果字符串,从左到右扩展。
根据 @mosvy 的评论,这首先出现于csh
但其行为与其他 shellbash
不同。csh
这种类型的大括号扩展也存在于glob(3)
.
还有一种大括号扩展{a..z}
是3.0之后才出现的, 4.0bash
中添加了更多。bash
在打开globbing的shell中,在空文件夹中执行,返回以下结果
$ echo a[bc]d
a[bc]d
$ echo a{b,c}d
abd acd
作为对 @Jesse_b 的评论的回应,如果您处于交互式 shell 中并且两者都适用,那么a[bc]d
输入的麻烦会更少。例如grep pattern [ab][12].txt
。