2016-07-14 50 views
1

我之前在终端上玩过,发现我可以通过制作单字命令('ls','cat','python2.7','exit')与命令命名相同的文件或目录。然而,我不能执行'多字'命令('rm \ -rf *','ls -a','python2.7 \ test.py')(这也导致我发现你不能删除名为'-rf'的目录和'rm -rf *')除非参数是按字母顺序排列的。表面上看,当你传入*到bash时,它会按照字母顺序读取文件/目录的名称,并将每个连续的名称作为参数传递给前一个命令。例如:Bash:使用文件名作为通配符的命令

$ mkdir cat 
$ touch dog 
$ vim dog # at this point I put 'Hello!' into dog 
$ * 
Hello! 

为什么通配符不允许我带空格执行文件的命令,但允许我执行多个文件名的命令?谢谢!

编辑:也别名不工作的原因。例如:

$ alias lsa='ls -a' 
$ mkdir lsa 
$ * 
No command 'lsa' found, did you mean: 
    ... 
lsa: command not found 

任何人都知道这是为什么?

+0

不知道这个的目的是什么,只是不建议创建名为“sudo”的文件。 – pmod

+0

我只是觉得它很整洁,想知道一些关于它背后的机制的更多细节。不知道为什么它被启用。 –

+0

也许“strace *”将有助于理解... – pmod

回答

2

每个命令bash进程都受到几种扩展,然后bash将解释并处理结果。其中最后一个是路径名扩展,其中bash检查命令的单词(由以前的扩展和单词分割产生),其中包含任何未引号的特殊字符*,?[,并将这些单词解释为模式表示文件名称。所有扩展完成后,扩展命令中的所有重定向和变量赋值都将执行并从命令中删除。如果剩下任何单词,则首先将其作为要运行的命令的名称。这个词的出处并不重要。

在路径名扩展中,*匹配任何字符串,包括空字符串。当bash对仅包含*的单词执行路径名扩展时,它将扩展为工作目录中所有文件的名称,但以点(.)开头的文件除外。

因此,如果您的工作目录包含一个名为ls只是一个单一的文件,并执行命令*,bash的扩展了命令ls并执行它,产生输出ls。同样,如果目录的内容是echo,Hello,World!,那么当您执行命令*时,bash会将其展开为等效于echo Hello, 'World!',并且命令输出为Hello, World!

这并不像你认为的那样适用于带空格的文件名,因为每个匹配模式的文件名都被扩展为一个单词。这些不会随后分裂。 (Bash确实在扩展过程中执行了“分词”操作,但在路径名扩展之前会发生)。这通常是您想要的,否则诸如rm *之类的命令不会可靠地按照您的预期进行操作。

这不适用于别名,因为bash读取命令时扩展了别名,而不是在执行它们时。这有几个含义,但其中之一是在执行任何扩展之前解释别名。另一个是别名的替换文本受制于所有正常的扩展。