cat file | command
(这称为无用的使用猫),正确的方法应该是:
command < file
在第二,“正确”的方式 – 操作系统不必产生额外的过程。
尽管知道,我继续使用无用的猫有两个原因。第一 – 更美观 – 我喜欢数据只从左到右均匀移动。并且更容易用别的东西(gzcat,echo,…)替换cat,添加第二个文件或插入新的过滤器(pv,mbuffer,grep …)。
第二个原因 – 我“感觉”,在某些情况下可能会更快。更快,因为有2个进程,第一(猫)做阅读,第二做任何。它们可以并行运行,这意味着有时更快的执行。
我的逻辑是正确的(第二个原因)?
我不想防守对他的回应。毕竟,在我年轻的时候,我会写的命令为grep foo file.txt |切割… |剪切…因为每当你做频繁的单个greps,你学习文件参数的位置,它已经知道,第一个是模式,后面的是文件名。
这是一个有意识的选择,当我回答这个问题,使用猫,部分是因为一个“好味道”的理由(在Linus Torvalds的话),但主要是一个引人注目的功能的原因。
后者的原因更重要,所以我会先把它。当我提供一个管道作为解决方案,我期望它是可重用的。很可能在末端添加管道或者将其连接到另一个管道中。在这种情况下有一个grep的文件参数提高了可重用性,并且很可能如果没有错误消息,如果文件参数存在,那么默默地这样做。 e。 grep foo xyz | grep bar xyz | wc将给你在xyz包含bar的多少行,而你期待包含foo和bar的行数。在使用之前,必须在流水线中将参数更改为命令,容易出错。添加到无声故障的可能性,它成为一个特别阴险的做法。
前一个原因并不重要,因为很多“良好的品味”只是一个直觉的潜意识的理由,例如上面的沉默故障,你不能想到的时候,当一个需要教育的人说“但不是那只猫无用“。
但是,我也会努力让自己意识到前面提到的“好口味”的原因。这是因为Unix的正交设计精神。 grep不剪切和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因此我们违反了猫和全能的Unix的精神。好吧,如果是这样的情况,那么Unix需要一个不同的命令来读取一个文件的输出,并将其吐出到stdout(不分页它或任何只是一个纯吐温到stdout)。所以你会有这样的情况,你说猫file1 file2或你说狗file1和认真地记得避免cat file1避免获得奖,同时也避免了狗file1 file2,因为希望狗的设计会抛出一个错误,如果多个文件指定。
希望在这一点上,你同情Unix设计者不包括一个单独的命令,吐出一个文件到stdout,同时也命名cat连接,而不是给它一些其他名称。 < edit>删除了对<,<是一个高效的无复制功能,可以将文件分流到stdout,您可以将其放置在流水线的开头,因此unix设计者确实包含了一些特殊的< / edit>
下一个问题是为什么有重要的命令,只是吐吐一个文件或几个文件的连接到stdout,没有任何进一步的处理?一个原因是避免每个单独的Unix命令对标准输入进行操作,以了解如何解析至少一个命令行文件参数,并将其用作输入(如果存在)。第二个原因是避免用户必须记住:(a)文件名参数的位置;和(b)避免上述的静默管道漏洞。
这让我们了解为什么grep有额外的逻辑。基本原理是允许用户流畅用于经常使用并且在独立基础(而不是管道)上使用的命令。这是对正交性的轻微妥协,以显着提高可用性。不是所有的命令都应该这样设计,并且不频繁使用的命令应该完全避免文件参数的额外逻辑(记住额外的逻辑导致不必要的脆弱性(错误的可能性))。例外是允许文件参数,如在grep的情况下。 (顺便说一下,ls有一个完全不同的理由,不只是接受,但几乎需要文件参数)
最后,如果在指定文件参数时标准输入也可用,如果grep(但不一定是ls)等特殊命令产生错误,那么可以做的更好。这是合理的,因为为了用户方便,命令包括违反Unix的正交精神的逻辑。为了进一步方便用户, e。为了防止由静默故障引起的痛苦,这样的命令应当通过具有额外的逻辑来警告用户如果存在静默错误的可能性,则应当毫不犹豫地违反他们自己的违反。