为什么Bash在运行之前会扩展命令?

0 linux bash shell glob

我正在运行该命令find . -name *.bak并收到错误"Paths must precede expression"错误.这个问题已得到解答,答案非常好,但我不明白为什么bash在运行find命令之前扩展了外卡?原始的例子.

它说find . -name *.bak扩大到find . -name tim.bak example.bak.有人可以解释为什么它被扩展,我不明白为什么这个功能为globs是个好主意.

Gor*_*son 6

这是一个在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/执行somecommand.本文提供了更多示例.

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

正如您可能从上面所述,我总体上认为VMS方式更好.对于程序员来说,这是一项更多的工作,但在可用性和功能方面具有显着的优势.但我确信这是unix人中的少数观点,无论如何,它需要花费大量的努力来改变unix的工作方式,所以只要unix是unix,它就不会改变.