linux - 为什么命令在运行之前会被 Bash 展开?

标签 linux bash shell glob

我正在运行命令 find 。 -name *.bak 并收到错误 “路径必须先于表达式” 错误。这个问题已经回答了,回答的很好,但是我不明白的是,为什么 bash 在运行 find 命令之前扩展通配符? original example .

上面写着 find 。 -name *.bak 扩展为 find 。 - 名称 tim.bak example.bak。有人可以解释为什么要扩展它吗,我不明白为什么对 glob 具有此功能是个好主意。

最佳答案

这是一个在 Unix 历史上很早就做出的设计决定。文件名通配符在某些时候需要扩展,但是可以选择是否应该由命令解释器(又名 shell)完成,并将结果(匹配文件列表)交给可执行文件,或者命令解释器是否应该只将给定的内容传递给可执行文件,并让它进行扩展。不同的操作系统以不同的方式执行此操作; unix 是第一种,但 VMS(我在迁移到 unix 之前使用过)是第二种方式。两者各有优缺点。

  • unix 方式的主要优点是通配符扩展代码只需在一个地方编写和使用:在 shell 中。命令很简单,不必担心。其次,您可以通过在一个地方进行更改来改进/扩展匹配语法(例如 bash 的 extglob 语法)。第三,您可以在所有不同的命令之间获得一致的扩展语法(相对于必须为不同的命令学习不同的规则,例如基本的、扩展的、与 perl 兼容的正则表达式一团糟)。

  • VMS 方式的主要优点是可执行程序知道参数的含义,并且可以适本地更改/抑制扩展。例如,find 不会在当前目录中扩展通配符,grep 不会尝试扩展正则表达式模式,就好像它是文件通配符一样,scp 可以在远程计算机上 扩展通配符,等等。第二个优点是通配符可以以 unix 系统根本不允许的方式使用,因为程序有更深入地了解参数是如何指定的;例如 rename *.jpeg *.jpg 是(如果我没记错的话)一个非常好的 VMS 命令,它完全按照它看起来应该做的做。

    [编辑] 另一个优点是它避免了文件名被误认为命令选项的风险。对于 unix 方法,这可能是一个严重的安全问题,因为任何可以控制文件名的人也可以控制使用这些文件的命令和脚本。例如,创建名为“-e somecommand”的文件会导致 rsync -t * foo:src/ 在远程计算机上执行 somecommandThis article给出了更多的例子。

    每个程序都需要进行自己的通配符扩展并没有您想象的那么糟糕。有处理扩展的标准库函数,所以程序需要做的就是调用它,然后处理生成的文件列表,没什么大不了的。这些库函数可以像 shell 语法一样进行扩展,并且对它们进行标准化可以提供跨程序等方面的一致性。

您可能从上面可以看出,我总体上认为 VMS 方式更好。对于程序员来说,这需要多做一些工作,但在可用性和功能方面具有显着优势。但我敢肯定,这是 unix 人中的少数人的观点,而且无论如何,要改变 unix 的工作方式需要付出大量的努力,所以只要 unix 还是 unix,它就不会改变改变。

关于linux - 为什么命令在运行之前会被 Bash 展开?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50127424/

相关文章:

regex - 使用 '=~' 运算符的 Bash 正则表达式匹配意外失败

bash 从命令行参数设置变量

android - 从python输入adb shell

bash - 当我们将命令放在美元符号和括号 : $(command) 中时,它在 shell 中意味着什么

linux - 设备 sda2 上的缓冲区 I/O 错误,逻辑 block 66326416

linux - 如何非root模式下打开/dev/mem?

linux - .!(|.|git) 在 shell 启动的早期导致语法错误,但不会在稍后导致语法错误

Bash shopt xpg_echo

linux - 在 Linux 上提取两个字符串之间的子字符串

linux - 通过 bash 脚本从文本文件运行命令