3 回答
TA贡献1836条经验 获得超4个赞
直到今天我才意识到这个奖项,当时一些菜鸟试图将UUOC找我的答案之一。那是一个cat file.txt | grep foo | cut ... | cut ...
。我给了他一个想法,然后访问了他给我的链接,他提到了这个奖项的来源和这样做的做法。进一步的研究使我想到了这个问题。有些遗憾的是,尽管有意识地考虑,但没有一个答案包括我的理由。
我本不想在回应他时采取防御的态度。毕竟,在我年轻的时候,我会把命令写成grep foo file.txt | cut ... | cut ...
因为无论你做什么grep
我们学习了文件参数的位置,它已经知道第一个是模式,而后面的是文件名。
这是一个有意识的选择cat
当我回答这个问题时,部分原因是“品味好”(用LinusTorvalds的话来说),但主要是为了一个令人信服的功能原因。
后一个原因更重要,所以我会先说出来。当我提供管道作为解决方案时,我希望它是可重用的。很可能会在另一条管道的末端添加一条管道,或将其拼接到另一条管道中。在这种情况下,带有grep文件参数的grep会破坏可重用性,而且很可能会这样做。静默如果文件参数存在,则没有错误消息。I.,即grep foo xyz | grep bar xyz | wc
会给你多少行xyz
含bar
当您期望包含两者的行数时foo
和bar
。在使用之前,必须将参数更改为管道中的命令很容易出错。再加上沉默失败的可能性,它就变成了一种特别阴险的做法。
前一个原因也并非不重要,因为“有眼光“仅仅是直觉上的潜意识的理由,像上面的沉默失败,你无法想到的时候,当某个人需要教育时,说”但那猫不是无用的“。
但是,我也会努力使我提到的前一个“好品味”的原因有意识。这与Unix的正交设计精神有关。grep
不cut
和ls
不grep
。所以至少grep foo file1 file2 file3
违背了设计精神。做这件事的正交方法是cat file1 file2 file3 | grep foo
。现在,grep foo file1
只是一个特例grep foo file1 file2 file3
如果你不这样对待它,你至少是在消耗大脑的时钟周期,试图避免无用的猫奖。
这就引出了我们的论点grep foo file1 file2 file3
正在连接,而且cat
串连,所以它是适当的cat file1 file2 file3
但因为cat
没有连接到cat file1 | grep foo
因此我们违背了cat
以及万能的Unix。如果是这样的话,那么Unix将需要一个不同的命令来读取一个文件的输出并将其吐出到stdout(而不是对其进行分页,也不只是一个纯的stdout)。所以你会遇到你说的那种情况cat file1 file2
或者你说dog file1
认真地记住要避免cat file1
为了避免获奖,同时也要避免dog file1 file2
因为希望…的设计dog
如果指定多个文件,则会引发错误。
希望在这一点上,您同情unix设计器没有包含一个单独的命令来向stdout吐出一个文件,同时还命名了cat
而不是给它取别的名字。<edit>
删除不正确的注释<
事实上,<
是一种高效的不复制工具,可以将文件吐出到stdout,您可以将其定位在管道的开头,因此unix设计器确实包含了一些专门用于此的内容。</edit>
下一个问题是,为什么命令只是吐出一个文件或将几个文件连在一起,而不进行任何进一步的处理,这是很重要的呢?原因之一是避免让每个在标准输入上操作的Unix命令知道如何解析至少一个命令行文件参数,并在存在时将其用作输入。第二个原因是避免用户必须记住:(A)文件名参数的去处;(B)如上所述,避免沉默的管道错误。
这就引出了为什么grep
确实有额外的逻辑。其基本原理是允许用户流畅地使用频繁使用的命令和单枪匹马基础(而不是管道)。这是一个小妥协的正交性,以显著提高可用性。并不是所有的命令都是这样设计的,不经常使用的命令应该完全避免文件参数的额外逻辑(记住,额外的逻辑会导致不必要的脆弱性(bug的可能性)。例外情况是允许文件参数,如grep
。(顺便提一下,请注意ls
有一个完全不同的理由不仅接受,而且几乎需要文件参数)
最后,本可以做得更好的是,如果这样的特殊命令grep
(但不一定ls
)如果指定文件参数时标准输入也可用,则生成错误。
TA贡献1820条经验 获得超9个赞
不!
首先,在什么地方发生重定向并不重要。因此,如果您喜欢将方向重定向到命令的左边,那很好:
< somefile command
是相同的
command < somefile
第二,有n+1进程和子外壳在使用管道时发生。这是最明显较慢的。在某些情况下n应该是零(例如,当您重定向到shell内置的时候),所以使用cat
您正在添加一个完全不必要的新过程。
一般说来,每当你发现自己在使用管道时,就应该花30秒的时间来看看你是否能消除它。(但可能不值得花费超过30秒的时间。)下面是一些管道和过程经常被不必要地使用的例子:
for word in $(cat somefile); … # for word in $(<somefile); … (or better yet, while read < somefile)grep something | awk stuff; # awk '/something/ stuff' (similar for sed)echo something | command; # command <<< something (although echo would be necessary for pure POSIX)
添加回答
举报