如何修复 Broken Pipe 错误?

Jas*_*ltz 43 bash ruby .bash-profile rvm

我最近在获得 SSD 驱动器后重新安装了 Ubuntu 12.10 后重新安装了 RVM(按照http://rvm.io 上的说明进行操作)。

现在,当我输入: type rvm | head -1

我收到以下错误:

rvm is a function
-bash: type: write error: Broken pipe
Run Code Online (Sandbox Code Playgroud)

但是,如果我立即重复该命令,那么我只会收到:

rvm is a function
Run Code Online (Sandbox Code Playgroud)

而且看起来一切正常?发生了什么?我能做些什么来修复它?它并不总是发生。它似乎更加零星。我试图找到某种模式,但还没有。

use*_*686 62

在这种情况下看到“断管”很少见,但很正常。

当您运行 时type rvm | head -1,bashtype rvm在一个进程head -1中执行,在另一个进程中执行。1的标准输出type连接到管道的“写”端,标准输入head连接到“读”端。两个进程同时运行。

head -1进程从 stdin 读取数据(通常以 8 kB 的块为单位),打印出一行(根据-1选项),然后退出,导致管道的“读取”端关闭。由于该rvm函数很长(在被​​ bash 解析和重构后大约 11 kB),这意味着head退出时type还有几 kB 的数据要写出。

此时,由于type正在尝试写入另一端已关闭的管道 -损坏的管道 - 它调用的 write() 函数将返回一个 EPIPE 错误,翻译为“损坏的管道”。除了这个错误之外,内核还会向 发送 SIGPIPE 信号type,默认情况下它会立即终止进程。

(该信号在交互式 shell 中非常有用,因为大多数用户不希望第一个进程继续运行并试图无处写入。同时,非交互式服务会忽略 SIGPIPE – 这对于长时间运行的守护进程来说是不利的死于这样一个简单的错误——所以他们发现错误代码非常有用。)

但是,信号传递不是 100% 立即传递的,并且可能存在 write() 返回 EPIPE 并且进程在接收信号之前继续运行一小段时间的情况。在这种情况下,type在被 SIGPIPE 杀死之前,有足够的时间注意到失败的写入,转换错误代码,甚至将错误消息打印到 stderr。(错误消息说“-bash:type:”因为type是bash本身的内置命令。)

这在多 CPU 系统上似乎更常见,因为type进程和内核的信号传递代码可以在不同的内核上运行,实际上是同时运行的。

可以通过修补type内置(在 bash 的源代码中)以在它从 write() 函数接收到 EPIPE 时立即退出来删除此消息。

但是,这没有什么可担心的,它与您的rvm安装没有任何关系。

  • 多年来我一直通过“head -1”管道输出“ls”,今天我收到一条损坏的管道消息。 (2认同)

Huu*_*uuu 28

您可以通过插入管道以牺牲另一个进程为代价来修复损坏tail -n +1的管道,如下所示:

类型 rvm | 尾 -n +1 | 头-1

+1通知tail打印输入和遵循事物的第一道防线。输出将与tail -n +1不存在时完全相同,但该程序足够智能,可以检查标准输出并干净地关闭管道。不再有破损的管道

  • 看起来是一个很好的解决方案,但是在带有 tail 8.21 的 Ubuntu 14.04.2 上,我得到“tail: write error: Broken pipe”,这没有任何改进。 (7认同)
  • 我将进一步修改我的建议,尽管我会注意到我不认为 xargs 或 type 应该对 SIGPIPE 进行讨论,如下:`type rvm | (head -1 ; dd of=/dev/null)` 当然,这与其他建议类似,因为它导致所有输入都被处理,但 `dd` 应该是处理这些事情的最有效的程序。 (5认同)
  • 此处对 SIGPIPE 违规者的评论:https://mail-index.netbsd.org/tech-userlevel/2013/01/07/msg007110.html (4认同)
  • @RogerDueck 是正确的。我也在 Mandriva 系统上看到了类似的问题`find /var/lib/mysql -xdev -type f -daystart -mmin +5 -print0 | xargs -0 ls -ldt | 尾 -n +1 | head` 可靠地产生 `xargs: ls: 由信号 13` 终止。正如我们所知,问题是输入耗尽之一,实际上只有一个命令处理缓冲:dd。添加`| dd obs=1M` 到管道修复了我的用例的 SIGPIPE。 (2认同)

小智 9

让我们尝试一下yes,无限的流程打印是的......

\n\n

之前,yes进程在达到限制时会被 SIGPIPE 终止。

\n\n
\xe2\x9e\x9c set -o pipefail\n\xe2\x9e\x9c yes | head -n 1\ny\n\xe2\x9e\x9c echo $?        \n141\n
Run Code Online (Sandbox Code Playgroud)\n\n

我的解决方案

\n\n
\xe2\x9e\x9c yes | (head -n 1;dd status=none of=/dev/null)\ny\n\n\n# the process will still running and output to null\n
Run Code Online (Sandbox Code Playgroud)\n\n

你可以yes用你的程序替换。

\n

  • `cat > /dev/null` 也有效。事实上,就像 @user1686 所说,“EPIPE”与异步“SIGPIPE”之间的错误时间会影响错误代码。在我的 WSL2 系统中,回显 162 个或更多空行表现出从 0(忽略 EPIPE?)到 141(SIGPIPE,bash 退出代码 128+13)作为退出代码的转换。然后“cat”似乎消耗了管道的其余部分(就像 dd 一样)。 `$ { for((i=0;i<200;i++));做回声;完成} | { 头 -n 1;猫 > /dev/null; };回声$? 0` (2认同)