为什么管道到 cat 只是为了重定向?

OJF*_*ord 29 pipe io-redirection cat

我偶尔会看到这样的事情:

cat file | wc | cat > file2
Run Code Online (Sandbox Code Playgroud)

为什么要这样做?

结果(或性能)何时会(有利地)不同于:

cat file | wc > file2
Run Code Online (Sandbox Code Playgroud)

lar*_*sks 37

这两个例子都是cat 的无用用法。两者都等价于wc < file1 > file2. cat在此示例中没有理由使用,除非您将其cat file用作动态生成输出的临时替代品。

  • @IstvanChung:它们不是等价的。`wc &lt; file1` 导致 `wc` 运行,stdin 是一个常规可查找、可移动的文件 `file1` 的文件描述符。`猫文件1 | wc` 导致 `wc` 在 stdin 上使用不可查找的管道运行。 (21认同)
  • @alephzero 重读答案-`cat 文件| wc` 等价于 `wc &lt; file1`。 (13认同)
  • +1 最后一句话。通常,“无用”`cat` 是一个方便的占位符,可以在不重新排列管道的情况下弹出其他命令。 (10认同)
  • `cat` 的第一个用法在这里*不一定*没用。命令`wc file` 打印计数器*后跟文件名*。命令`cat file | wc` 不*不*打印文件名。第二个 `cat` 没用。`wc file1 file2` 打印两行计数,每个文件一行(加上文件名)。`cat file1 file2 | wc` 打印带有总计数的一行,没有文件名。 (7认同)
  • @IstvanChung:有趣的是,在我的系统上,它们实际上 * 不 * 等效。`cat file |wc` 用比 `wc &lt;file` 多的空格分隔行/单词/字符计数。我不知道为什么。 (3认同)

Sté*_*las 32

cat file | wc | cat > file2
Run Code Online (Sandbox Code Playgroud)

通常是两个无用的用途,cat因为它在功能上等同于:

< file wc > file2
Run Code Online (Sandbox Code Playgroud)

但是,可能存在以下情况:

cat file | wc -c
Run Code Online (Sandbox Code Playgroud)

超过

< file wc -c
Run Code Online (Sandbox Code Playgroud)

那就是禁用许多wc实现对常规文件所做的优化。

对于常规文件,无需读取文件的全部内容即可获取文件中的字节数,只需对其进行stat()系统调用并检索存储在 inode 中的大小即可。

现在,人们可能希望读取文件,例如,因为:

  • stat()信息不能被信任(如在一些文件/proc/sys在Linux上):

    $ < /sys/class/net/lo/mtu wc -c
    4096
    $ cat /sys/class/net/lo/mtu | wc -c
    6
    
    Run Code Online (Sandbox Code Playgroud)
  • 一个人想检查可以读取多少数据(例如硬盘驱动器出现故障的情况)。
  • 人们只是想获得有关数据读取速度的基准。
  • 人们希望将文件的内容缓存在内存中。

当然,这些都是例外。在一般情况下,< file wc -c出于性能原因,您宁愿使用。


现在,您可以想象可能想要使用的更牵强的场景cat file | wc | cat > file2

  • 可能wc有一个 apparmor 配置文件或其他安全机制,禁止它在允许的情况下读取或写入文件cat(这是闻所未闻的)
  • 也许cat能够处理大(如 > 2 32字节)文件,但不能wc在该系统上处理(过去某些系统上的某些命令需要类似的东西)。
  • 也许有人想要wc(也是第一个cat)运行并读取整个文件(并在最后一分钟被杀死),即使file2无法打开写入。
  • 也许有人想隐藏打开或阅读file. 虽然wc < file > file2 || :会更有意义。
  • 也许一个人想隐藏(从输出lsof(清单打开的文件))的事实,他从得到一个字计数file或者他存储在字计数file2


小智 17

虽然我不同意说这是“对 cat 的无用使用”的论点,但可能有以下原因:

在许多语言(包括英语)中,单词和句子是从左到右阅读的,因此以相同的方式显示数据流可以让读者看起来更自然。

第二个原因cat可能是屏蔽返回码。如:

$ wc < /etc/passw
sh: /etc/passw: Cannot find or open the file.
$ echo $?
1
Run Code Online (Sandbox Code Playgroud)

鉴于cat

$ wc < /etc/passw | cat
sh: /etc/passw: Cannot find or open the file.
$ echo $?
0
Run Code Online (Sandbox Code Playgroud)

如果外壳已经set -e设置,这可以发挥作用。在第一个示例中,这将在之后中止 shell,wc而在后一个示例中它将继续。显然还有其他方法可以解决这个问题。

此外,这两个语句(即有或没有 cat)的性能差异可以忽略不计(尤其是在今天的机器上),如果这很重要,shell 是使用错误的语言。

  • 有趣的言论。只是我对数据流从左到右表示的注释:您也可以通过重定向轻松实现这一点:`&lt; file1 wc &gt; file2` (6认同)
  • 这在实践中不是一个好主意。如果你想吞下错误,`|| true` 比 `| 更加地道和明显。猫`。 (6认同)
  • @pabouk - 哇!我不知道你能做到这一点。 (2认同)
  • @pabouk 所说的:重定向可以出现在命令行的任何位置,至少在 GNU bash 中,因此“从左到右阅读”不是使用 `cat` 代替重定向的有效参数。 (2认同)

pts*_*pts 9

让我们假设progfork 一个新的子进程并退出,新的子进程向其标准输出写入一些内容然后退出。

然后命令

prog
Run Code Online (Sandbox Code Playgroud)

不会等待子进程退出,它会提前显示 shell 提示。但是命令

prog | cat
Run Code Online (Sandbox Code Playgroud)

将等待 的标准输入上的 EOF cat,这有效地等待子进程退出。所以这是一个有用的用法cat