回声[[:digit:]]的异常行为


Answers:


34

因为它们是两个不同的东西。这{1,2,3}括号扩展的示例。该{1,2,3}结构由shell扩展,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也会首先对其进行处理,但是这次将其作为shell glob处理。它的运行方式与您运行时echo *将打印当前目录中所有文件的方式相同。但是,它[[: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都只打印外壳告诉它要打印的内容,而在第二种情况下,由于glob匹配某物(/etc),因此它被告知要打印该东西。

因此,由于您没有名称完全由一位数字组成的文件或目录([[:digit:]]将与之匹配),因此将全局扩展为自身,您将得到:

$ echo [[:digit:]]
[[:digit:]]

现在,尝试创建一个名为5并运行相同命令的文件:

$ echo [[:digit:]]
5

并且如果有多个匹配文件:

$ touch 1 5       
$ echo [[:digit:]]
1 5

man bashnullglob选项的说明中记录了这种情况(这些情况),该选项可以关闭此行为:

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

$ 

4
另请参阅shopt -s failglob以获取类似于现代外壳(如zsh或)的更有用的行为fish
斯特凡Chazelas

我同意斯特凡(Stéphane)的用法failglobnullglob可能会导致意外问题,例如,粘贴恰好具有的URL时?
凯文(Kevin)

1
当然,我只是提到nullglob要说明该模式被shell解释为glob。
terdon

14

{1,2,3}大括号扩展,不考虑其含义扩展为列出的单词。

[...]是一个字符组,用于文件名扩展(或通配符或glob),类似于星号*和问号?。它与其中列出的任何单个字符或作为命名组成员的字符(例如[: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还是echoor 都没关系rm。另请注意,如果引用了其中任何一个,则将不会对其进行扩展:

$ bash -c 'echo "[[:digit:]]"'         # even though matching files still exist
[[:digit:]]
$ bash -c 'echo "{1,2,3}"'
{1,2,3}

感谢您的回答,这是Linux的新手,所以请允许我问您echo与文件1 3有何关系,它的功能是将其参数输出到stdout,而不是就我所知搜索文件
AbdAllah Talaat

1
@AbdAllahTalaat实际上与回声无关。外壳程序(例如bash)将[[:digit:]] 传递给之前先对其进行“扩展” echo,所以echo永远不会看到[[:digit:]],只能看到1 3。您可以通过运行查看set -x实际运行情况,该命令将打印正在运行的实际命令(运行set +x以再次将其关闭)。
terdon

@AbdAllahTalaat,在运行之前echoshell不会查找文件echo
ilkkachu

特别是因为我认为在DOS / Windows中,这些实用程序会扩展通配符,而不是shell。(我可能错了)
ilkkachu

对不起,我将正确答案转移到了tedron的答案上,因为他的评论包含了bash是工作无法回响的意思……他的回答也包含了这个意思..大家都帮助了我……我希望我能把您所有答案和评论的正确答案
AbdAllah Talaat

4

{1,2,3}(例如,{1..3}括号扩展。它们在命令执行之前由外壳程序解释。

[[:digit:]]是与模式匹配的令牌,但是您没有在与该模式匹配的任何文件的位置使用它。如果您使用没有匹配项的模式匹配项,它将扩展为自身:

$ echo [[:digit:]]; touch 3; echo [[:digit:]]
[[:digit:]]
3

不,正如其他答案正确指出的那样,该模式与文件名匹配。
Toby Speight,
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.