shell - 用猫没用?

标签 shell command-line cat

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

cat file | command

(这被称为猫的无用使用),正确的方法应该是:
command < file

在第二种“正确”方式中 - 操作系统不必产生额外的进程。
尽管知道这一点,但我继续使用无用的 cat 有两个原因。
  • 更美观 - 我喜欢数据仅从左到右均匀移动。而且更容易更换cat使用其他内容( gzcatecho 、...),添加第二个文件或插入新过滤器( pvmbuffergrep ...)。
  • 我“感觉”在某些情况下它可能会更快。更快,因为有 2 个进程,第一个 ( cat ) 执行读取,第二个执行任何操作。它们可以并行运行,这意味着有时执行速度更快。

  • 我的逻辑是否正确(第二个原因)?

    最佳答案

    直到今天,当一些菜鸟试图钉 UUOC 时,我才知道该奖项。我的答案之一。这是一个 cat file.txt | grep foo | cut ... | cut ... .我给了他一点我的想法,只有在这样做之后才访问了他给我的链接,其中提到了该奖项的起源和这样做的做法。进一步的搜索使我想到了这个问题。有点不幸的是,尽管有意识地考虑过,但没有一个答案包含我的理由。

    我本不想在回应他时采取防御态度。毕竟,在我年轻的时候,我会把命令写成 grep foo file.txt | cut ... | cut ...因为每当你做频繁的单例grep s 您了解了文件参数的位置,并且已经知道第一个是模式,后面的是文件名。

    使用 cat 是有意识的选择当我回答这个问题时,部分是因为“品味”的原因(用 Linus Torvalds 的话),但主要是出于令人信服的功能原因。

    后一个原因更重要,所以我先说出来。当我提供管道作为解决方案时,我希望它是可重用的。很可能在另一条管道的末尾添加或拼接一条管道。在这种情况下,grep 的文件参数会破坏可重用性,并且很可能在文件参数存在的情况下静默执行而不会出现错误消息。即grep foo xyz | grep bar xyz | wc会给你多少行 xyz包含 bar而您期望包含 foo 的行数和 bar .在使用管道之前必须更改命令的参数很容易出错。再加上无声失败的可能性,它就变成了一种特别阴险的做法。

    前一个原因也不是不重要,因为很多“good taste
    只是对于诸如上述无声失败之类的事情的直观潜意识基本原理,当某些需要教育的人说“但那只猫不是无用的”时,您无法想到正确的方法。

    但是,我也会尽量注意我提到的前一个“好品味”的原因。这个原因与 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 将需要一个不同的命令来读取一个文件的输出并将其吐出到标准输出(而不是对其进行分页或任何纯粹的吐出到标准输出)。所以你会遇到你说 cat file1 file2 的情况。或者你说dog file1并认真记住避免cat file1避免获得奖励,同时也避免dog file1 file2因为希望 dog 的设计如果指定了多个文件,则会抛出错误。

    希望在这一点上,您对 Unix 设计者表示同情,因为他们没有包含一个单独的命令来将文件输出到 stdout,同时还命名为 cat。用于连接而不是给它一些其他名称。 <edit> 删除了对 < 的错误评论,事实上,<是一种高效的非复制工具,可以将文件输出到标准输出,您可以将其定位在管道的开头,因此 Unix 设计者确实为此包含了一些专门的内容 </edit>

    下一个问题是为什么让命令只将一个文件或几个文件的串联输出到标准输出而不进行任何进一步处理很重要?一个原因是避免让对标准输入进行操作的每个 Unix 命令都知道如何解析至少一个命令行文件参数并将其用作输入(如果存在)。第二个原因是为了避免用户必须记住:(a) 文件名参数在哪里; (b) 避免上面提到的静默管道错误。

    这让我们明白为什么 grep确实有额外的逻辑。其基本原理是允许用户流畅地使用频繁且独立使用的命令(而不是作为管道)。为了显着提高可用性,这是正交性的轻微折衷。并不是所有的命令都应该这样设计,不经常使用的命令应该完全避免文件参数的额外逻辑(记住额外的逻辑会导致不必要的脆弱性(错误的可能性))。异常(exception)是允许文件参数,例如 grep . (顺便说一句,请注意 ls 有一个完全不同的理由不仅接受而且几乎需要文件参数)

    最后,如果使用诸如 grep 之类的特殊命令,本可以做得更好。 (但不一定是 ls )如果在指定文件参数时标准输入也可用,则会生成错误。

    关于shell - 用猫没用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11710552/

    相关文章:

    linux - 在命令中传递单词

    Java - 来自 Windows 命令行但不是 Eclipse 的 classNotFound 异常

    bash - Bash脚本错误与cat和if

    regex - grep/regex找不到重音词

    unix - 如何连接大量文件

    linux - SSH : how to assign specifics directories to each user?

    bash - shell 中的 <<EOF 和 <<\EOF heredocs 有什么区别

    linux - slurm 脚本给出 "command not found"

    mysql - 如何在没有 DROP 数据库权限的情况下从命令行删除所有 MySQL 表?

    database - MongoDB 无法识别的选项 --install