Bash: 使用文件名作为带有通配符的命令

Bash: Using filenames as commands with the wildcard

我早些时候在我的终端上玩了一下,发现我可以通过制作一个与命令同名的文件或目录。但是,我无法执行 'multi-word' 命令('rm\ -rf *'、'ls -a'、'python2.7\ test.py')(这也让我发现您无法删除名为“-rf”的目录' with 'rm -rf *') 除非参数按字母顺序排列。看起来,当您将 * 传递给 bash 时,它会按字母顺序读取 files/directories 的名称,并将每个连续的名称作为参数传递给前一个命令。示例:

$ 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

有人知道这是为什么吗?

每个命令 bash 处理在 bash 解释和作用于结果之前都要进行多种扩展。最后一个是路径名扩展,其中 bash 检查命令的单词(由先前的扩展和单词拆分生成)是否包含任何未加引号的特殊字符 *?, 和 [, 并将这些词解释为代表文件名的模式。执行所有扩展后,将执行扩展命令中的任何重定向和变量赋值,并从命令中删除。如果还有任何单词,则第一个单词将作为 运行 的命令名称。这个词的出处并不重要。

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

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

对于其中包含空格的文件名,这并不像您想象的那样有效,因为每个与模式匹配的文件名都被扩展为一个单词。这些随后不会拆分。 (Bash 确实执行 "word splitting" 作为扩展过程的一部分,但这发生在 之前 路径名扩展。)这通常是你想要的,否则命令如rm * 不会可靠地做你期望的事情。

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