我想问:
为什么echo {1,2,3}
扩展为 1 2 3 这是预期的行为,而echo [[:digit:]]
返回[[:digit:]]
而我期望它打印从0
到 的所有数字9
?
答案1
因为它们是两种不同的东西。这{1,2,3}
是一个例子大括号扩展。这{1,2,3}
被扩展通过外壳,echo
甚至在看到它之前。如果使用以下命令,您可以看到会发生什么set -x
:
$ set -x
$ echo {1,2,3}
+ echo 1 2 3
1 2 3
如您所见,该命令echo {1,2,3}
扩展为:
echo 1 2 3
然而,[[:digit:]]
是一个POSIX 字符类。当你把它交给echo
,shell 也会首先处理它,但这次它被作为一个壳球。它的工作方式与运行相同,echo *
它将打印当前目录中的所有文件。 But[[:digit:]]
是一个可以匹配任何数字的 shell glob。现在,在 bash 中,如果 shell glob 不匹配任何内容,它将扩展到自身:
$ echo /this*matches*no*files
+ echo '/this*matches*no*files'
/this*matches*no*files
如果 glob 确实匹配某些内容,则会打印:
$ echo /e*c
+ echo /etc
/etc
在这两种情况下,echo
只打印 shell 告诉它打印的任何内容,但在第二种情况下,由于 glob 匹配某些内容 ( /etc
),所以它被告知打印该内容。
因此,由于您没有任何名称由一位数字(这是匹配的数字[[:digit:]]
)组成的文件或目录,因此 glob 会扩展到自身,您将得到:
$ echo [[:digit:]]
[[:digit:]]
现在,尝试创建一个名为的文件5
并运行相同的命令:
$ echo [[:digit:]]
5
如果有多个匹配文件:
$ touch 1 5
$ echo [[:digit:]]
1 5
这(在某种程度上)记录在关闭此行为的选项man bash
的解释中:nullglob
nullglob
If set, bash allows patterns which match no files (see
Pathname Expansion above) to expand to a null string,
rather than themselves.
如果您设置此选项:
$ rm 1 5
$ shopt -s nullglob
$ echo [[:digit:]] ## prints nothing
$
答案2
{1,2,3}
是大括号扩展,它扩展到列出的单词,而不考虑其含义。
[...]
是一个字符组,用于文件名扩展(或通配符,或通配符)类似于星号*
和问号?
。它匹配其中列出的任何单个字符,或属于命名组成员的字符(例如[:digit:]
列出的字符)。大多数 shell 的默认行为是,如果没有与其匹配的文件,则将通配符保留原样。
(请注意,您无法真正将通配符/模式转换为它要匹配的字符串集。星号可以匹配任何长度的任何字符串,因此扩展包含它的任何模式将产生无限的字符串列表。)
所以:
$ bash -c 'echo [[:digit:]]' # bash leaves it as-is
[[:digit:]]
$ zsh -c 'echo [[:digit:]]' # zsh by default complains if no match
zsh:1: no matches found: [[:digit:]]
$ touch 1 3 d i g t
$ bash -c 'echo [[:digit:]]' # now there are two matches
1 3 # note that d, i, g and t do NOT match
但仍然:
$ bash -c 'echo {1,2,3}'
1 2 3
两者都由 shell 扩展ls
,无论您运行的命令是、 或echo
或,都没有关系rm
。另请注意,如果引用其中任何一个,它们将不会被扩展:
$ bash -c 'echo "[[:digit:]]"' # even though matching files still exist
[[:digit:]]
$ bash -c 'echo "{1,2,3}"'
{1,2,3}
答案3
{1,2,3}
(例如{1..3}
是大括号扩展。它们在命令执行之前由 shell 解释。
[[:digit:]]
是一个模式匹配令牌,但您没有在任何与该模式匹配的文件的位置使用它。如果您使用没有匹配项的模式匹配,它将扩展到自身:
$ echo [[:digit:]]; touch 3; echo [[:digit:]]
[[:digit:]]
3