【问题标题】:Why do commands get expanded by Bash before they run?为什么命令在运行之前会被 Bash 扩展?
【发布时间】:2018-10-12 03:17:50
【问题描述】:

我正在运行命令 find . -name *.bak 并收到错误 "Paths must precede expression" 错误。这个问题已经回答了,答案还挺好的,但是我不明白的是为什么bash在find命令运行之前会扩展通配符? original example.

它说find . -name *.bak 扩展为find . -name tim.bak example.bak。有人能解释一下为什么要扩展它吗,我不明白为什么为 glob 提供这个功能是个好主意。

【问题讨论】:

    标签: linux bash shell glob


    【解决方案1】:

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

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

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

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

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

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

    【讨论】:

    • 好答案+1!对我来说,很明显它应该由shell负责
    【解决方案2】:

    UNIX 的创始人之一丹尼斯·里奇给出了这样的解释:

    “把这个扩展机制放到shell里面有几个好处: 代码只出现一次,所以不会浪费空间,而且命令一般 无需采取特别行动;该算法肯定会被应用 统一。”

    D.M.Ritchie,Unix Time-Sharing System: A Retrospective BSTJ 1978 年 7 月至 8 月

    【讨论】:

      【解决方案3】:

      一个非常简短的回答:

      这是Bash 的工作方式,它总是扩展他所能做的,用它们的值替换变量,使用环境变量(例如$PATH),解释别名并传递结果(对应的参数)到您正在调用的“proper”命令(从$PATH 中提取)。参数扩展可以看作是 bash 众多职责之一。

      想象一下,如果您没有此功能,则需要为您开发的每个程序实现此功能,以正确扩展参数(在工作目录或您指向的目录中使用相应的文件)。简而言之,这将是一场噩梦!!!这就是为什么它集中在 bash 中。

      最后但并非最不重要的一点是,对于您的 find 命令,请以这种方式更改它以避免来自 bash 的任何干扰。通过这样做,find 命令将接收文件名的正则表达式,以便正确搜索和管理它

      find . -name '*.bak'
                   ^     ^
      

      Shell 职责列表:

      http://www.informit.com/articles/article.aspx?p=31480&seqNum=4 http://ptgmedia.pearsoncmg.com/images/chap3_0672324903/elementLinks/03fig08.jpg http://tldp.org/LDP/abs/html/x9644.html

      【讨论】:

        猜你喜欢
        • 2015-06-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-12
        • 1970-01-01
        • 2019-10-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多