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

没用的猫?

/ 猿问

没用的猫?

茅侃侃 2019-05-30 16:02:58

没用的猫?

这可能在许多常见问题中-而不是使用:

cat file | command

(这被称为对CAT的无用使用),正确的方式应该是:

command < file

在第二,“正确”的方式-操作系统不需要产生额外的进程。
尽管我知道这一点,但我继续使用无用的猫有两个原因。

  1. 更美观-我喜欢数据只从左向右一致移动。而且更容易替换cat用别的东西(gzcatecho,添加第二个文件或插入新筛选器(pvmbuffergrep ...).

  2. 我“觉得”在某些情况下可能会更快。更快,因为有两个进程,第一个(cat)阅读,第二个做任何事情。它们可以并行运行,这意味着有时执行速度更快。

我的逻辑正确吗(第二个原因)?


查看完整描述

3 回答

?
HUH函数

直到今天我才意识到这个奖项,当时一些菜鸟试图将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
?
春华秋衣

不!

首先,在什么地方发生重定向并不重要。因此,如果您喜欢将方向重定向到命令的左边,那很好:

< 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
?
DIEA

用UUoC版本,cat必须将文件读入内存,然后将其写入管道,命令必须从管道读取数据,因此内核必须复制整个文件。而在重定向情况下,内核只需复制文件一次。做一件事比做三次来得快。

使用:

cat "$@" | command

是完全不同的,也不一定是无用的。cat。如果命令是接受零或多个文件名参数并依次处理这些参数的标准筛选器,则仍然没有用处。考虑tr命令:它是一个纯过滤器,它忽略或拒绝文件名参数。要将多个文件提供给它,您必须使用cat如图所示。(当然,还有一个单独的讨论tr不是很好;没有真正的理由不能把它设计成一个标准的过滤器。)如果您希望命令将所有输入视为单个文件而不是多个单独的文件,则这也可能是有效的,即使命令将接受多个单独的文件:例如,wc就是这样的命令。

这是cat single-file无条件无用的案子。


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

添加回答

回复

举报

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