我正在运行命令find . -name *.bak
并收到错误"Paths must precede expression"
错误。这个问题已得到解答,答案非常好,但我不明白为什么bash在运行find命令之前扩展了外卡? original example
它说find . -name *.bak
已扩展为find . -name tim.bak example.bak
。有人可以解释为什么它会被扩展,我无法理解为什么将这个功能用于globs是个好主意。
答案 0 :(得分:6)
这是一个在unix历史中很早就做出的设计决策。文件名通配符需要在某个时候进行扩展,但是可以选择是否应该由命令解释器(也称为shell)完成,并将结果(匹配文件列表)传递给可执行文件,或者是否命令解释器应该只传递它给可执行文件的内容,并让它进行扩展。不同的操作系统以不同的方式执unix做的第一个,但VMS(我在迁移到unix之前使用)是第二种方式。两者都有优点和缺点。
unix方式的主要优点是通配符扩展代码只需要在一个地方编写和使用:在shell中。简单的命令不必担心它。其次,您可以通过在一个地方中进行更改来改进/扩展匹配语法(例如,bash&#39的extglob语法)。第三,在所有不同命令之间获得一致的扩展语法(与必须学习不同命令的不同规则,如基本与扩展与perl兼容的正则表达式混乱)。
VMS方式的主要优点是可执行程序知道参数的含义,并可以适当地改变/抑制扩展。例如,find
会知道不在当前目录中展开通配符,grep
会知道不会尝试扩展正则表达式模式,就好像它是文件通配符一样,scp
可能会扩展远程计算机上的通配符 等。第二个优点是通配符可以以unix系统不允许的方式使用,因为程序可以更深入地了解参数是如何规定;例如rename *.jpeg *.jpg
是(如果我没记错的话)一个非常好的VMS命令,它完全按照它应该做的那样。
[编辑]另一个优点是它避免了文件名被误认为命令选项的风险。这可能是unix方法的一个严重的安全问题,因为任何可以控制文件名的人也可以控制命令&与这些文件一起使用的脚本。例如,创建名为" -e somecommand"的文件。会导致rsync -t * foo:src/
在远程计算机上执行somecommand
。 This article提供了更多示例。
每个程序进行自己的通配符扩展的需求并不像你想象的那么糟糕。有标准的库函数来处理扩展,所以程序需要做的就是调用它然后处理生成的文件列表,没什么大不了的。这些库函数可以像shell语法一样扩展,并且标准化它们可以提供程序之间的一致性等。
正如您可能从上面所述,我总体上认为VMS方式更好。它为程序员提供了更多的工作,但在可用性和功能方面具有显着优势。但我确信这是unix人中的少数观点,无论如何,它会采取大规模的努力来改变unix的做法,所以只要unix是unix,它不会改变。
答案 1 :(得分:1)
一个非常简短的回答:
这是Bash
的工作方式,它总是扩展他的能力,用它们的值替换变量,使用环境变量(例如$PATH
),解释别名并传递结果(相应的参数)到您正在调用的“正确”命令(从$PATH
中提取)。论证扩展可以被看作是众多责任之一。
想象一下,如果您没有此功能,则需要为每个程序实现这一功能,即正确扩展参数(使用工作目录中或您指向的目录中的相应文件)。简而言之,这将是一场噩梦!这就是为什么它集中在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
答案 2 :(得分:0)
UNIX的创始人之一Dennis Ritchie给出了这样的解释:
“将此扩展机制放入shell中有几个优点: 代码只出现一次,因此通常不会浪费空间和命令 不需要采取任何特别行动;该算法肯定会被应用 均匀“。
D.M.Ritchie,Unix Time-Sharing System: A Retrospective BSTJ 1978年7月至8月