如何避免使用 cat 命令中的管道损坏?

如何避免使用 cat 命令中的管道损坏?

为什么这个简单的命令在使用 emacs shell (eshell) 时失败?

cat file.txt | wc 

我有一个包含 10241 行的文件。每行少于 50 个字符。在我启动此命令的情况下,大约 90% 的情况下,它会给出错误的结果,即行计数。尽管如此,没有给出错误消息。

看起来管道破裂是一个很常见的话题,但我还没有找到任何合理的解释。此外,没有人提出任何解决方法。我怎样才能让这个简单的命令可靠地工作?

当然,我也可以直接逃跑wc file.txt。但我正在寻找一种更通用的解决方案,其中任何工具都可以正常工作 Piped cat: cat file.txt | any_tool_here

细节

我使用的是CentOS 5。使用时出现此问题eshell(emacs shell)。我正在使用 GNU Emacs 24.5.2。

实验

结果示例cat file.txt | wc(预期:第一列始终为 10241)。

  1. 8568 25706 110571
  2. 9837 29513 126947
  3. 5395 16187 69615
  4. 9202 27608 118757
  5. 7299 21899 94199
  6. 9837 29513 126947

结果示例使用wc file.txt

  1. 10241 30723 132156
  2. 10241 30723 132156
  3. 10241 30723 132156
  4. 10241 30723 132156
  5. 10241 30723 132156
  6. 10241 30723 132156

cat 命令本身(单独执行时)工作正常。我使用以下命令验证了它(几次)cat file.txt > file2.txt:。然后,我比较了这两个文件,它们是相同的。

答案1

从有关所使用的 shell 的信息来看 ( eshell),该 shell 的流处理方面似乎是罪魁祸首。通常,管道意味着打开管道的两端+ fork/exec,因此您会得到两个共享管道文件描述符的进程,并且通信直接通过内核进行。这样,就不会丢失任何东西 - 它保证是安全的(尽管如果管道或任何涉及的流被缓冲,您可能必须等待第一个进程正常退出才能刷新流的最后一个块)。

从摘录来看电子外壳手册

Eshell 不能替代 bash 或 zsh 等系统 shell。当您想要在 Emacs 和外部进程之间移动文本时,请使用 Eshell;如果您只想将输出从一个外部进程通过管道传输到另一个(然后是另一个,依此类推),请使用系统 shell,因为 Emacs 的 IO 系统是面向缓冲区的,而不是面向流的,并且在此类任务中效率非常低。如果您想在 Eshell 中编写 shell 脚本,请不要这样做;要么编写 elisp 库,要么使用系统 shell。

eshell 没有以正常方式执行此操作,而是使用其“缓冲区”(emacs 的打开文件表示)作为数据的中间存储来伪造管道,并且(无需进一步研究)我猜想在某些时候wc会执行read,并emacs以空块响应(返回 0read表示流已结束),而不是等待第一个程序的更多输入来填充缓冲区。如果是这样的话,就意味着 eshell 在处理管道时不仅效率低下而且还存在缺陷。

相关内容