为了账号安全,请及时绑定邮箱和手机立即绑定

没用的猫?

没用的猫?

茅侃侃 2019-05-30 16:02:58
没用的猫?这可能在许多常见问题中-而不是使用:cat file | command(这被称为对CAT的无用使用),正确的方式应该是:command < file在第二,“正确”的方式-操作系统不需要产生额外的进程。尽管我知道这一点,但我继续使用无用的猫有两个原因。更美观-我喜欢数据只从左向右一致移动。而且更容易替换cat用别的东西(gzcat, echo,添加第二个文件或插入新筛选器(pv, mbuffer, grep ...).我“觉得”在某些情况下可能会更快。更快,因为有两个进程,第一个(cat)阅读,第二个做任何事情。它们可以并行运行,这意味着有时执行速度更快。我的逻辑正确吗(第二个原因)?
查看完整描述

3 回答

?
HUH函数

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会给你多少行xyzbar当您期望包含两者的行数时foobar。在使用之前,必须将参数更改为管道中的命令很容易出错。再加上沉默失败的可能性,它就变成了一种特别阴险的做法。

前一个原因也并非不重要,因为“有眼光“仅仅是直觉上的潜意识的理由,像上面的沉默失败,你无法想到的时候,当某个人需要教育时,说”但那猫不是无用的“。

但是,我也会努力使我提到的前一个“好品味”的原因有意识。这与Unix的正交设计精神有关。grepcutlsgrep。所以至少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)如果指定文件参数时标准输入也可用,则生成错误。


查看完整回答
反对 回复 2019-05-30
?
慕妹3146593

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)


查看完整回答
反对 回复 2019-05-30
  • 3 回答
  • 0 关注
  • 593 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信