在过去的几个月里,我的系统出现了一个问题。那就是管道损坏错误:
# Solution:
# silenced by replacing /bin/bzip2 -> bzip2-reference
# to /bin/bzip2 -> lbzip2
$ man man
#err# bzip2: I/O or other error, bailing out. Possible reason follows.
#err# bzip2: Broken pipe
#err# Input file = (stdin), output file = (stdout)
#err#
#err# bzip2: I/O or other error, bailing out. Possible reason follows.
#err# bzip2: Broken pipe
#err# Input file = (stdin), output file = (stdout)
# Solution:
# silenced by using awk: find -type f -name '*.pdf' | awk 'NR==1'
find -type f -name '*.pdf' | head -1
#err# find: ‘standard output’: Broken pipe
#err# find: write error
# I don't know how to silence the rest of these
tar tvf archive.tar | head
#err# tar: stdout: write error
sed $'s/\t/\t-\t/' table.tsv | head | column -ts $'\t' -R 1;
#err# sed: couldn't write 42 items to stdout: Broken pipe
已安装的软件包:
# distro: gentoo
app-shells/bash-5.1_p16-r6: /usr/bin/bash
app-arch/tar-1.35: /usr/bin/gtar
sys-apps/findutils-4.9.0-r2: /usr/bin/gfind
sys-apps/sed-4.9: /usr/bin/gsed
sys-libs/glibc-2.38-r10:
sys-apps/coreutils-9.4:
sys-apps/systemd-255.3-r1:
附加系统信息:
grep ^Sig /proc/self/status
#out# SigQ: 3/256943
#out# SigPnd:0000000000000000
#out# SigBlk:0000000000000000
#out# SigIgn:0000000000001000
#out# SigCgt:0000000000000400
# Login via vt1 (virtual terminal), then invoke startx for display server
我想这里的好朋友都知道Unix 哲学:“避免不必要的输出”规则。考虑到 90% 的计算机使用都是通过终端进行的,这种垃圾邮件是非常不受欢迎的。
我正在努力思考解决方案:
- 替换实现,
为bzip2-reference
lbzip2
。 - 更换用法,
为head
awk 'NR<11'
。- 我不同意,断开管道听起来是个合理的做法。如果标准输入是 GiB?TiB?无限?curl?串行?怎么办?
- 添加
2>/dev/null
到每个管道命令中。你知道为什么这是一个坏主意。 - 降级软件包。我不能再这样做了。无论如何我都想保持最新状态。
- 添加补丁
/etc/portage/patches/
。这听起来是最合理的解决方案,但其实不合理。
进一步说,这似乎会导致整个管道文本惯例man man
被破坏,head
被破坏。
发生了什么?我感觉我对发生的事情一无所知。一定有人知道。所以,如果最近有人提到由于管道破裂而导致病毒核熔毁,从而引发了这一系列垃圾邮件,我将不胜感激。
也许我需要编辑一些简单的文件来在/etc/
系统范围内禁用此策略。也许这是一个 GNU 问题,解决方案是迁移出 GNU 堆栈。也许我可以设置一些 ENV 变量/etc/profile
。也许我需要应用一个编译时标志。必须有。
答案1
程序没有改变。它们总是在遇到写入错误时输出消息,并且“管道损坏”(-EPIPE)始终是返回给写入器的错误代码,以防读取器提前退出。
通常情况下,内核除外终止进程那将会接收错误代码(通过发出 SIGPIPE),这样它就永远没有机会输出错误消息。
在 shell 管道中,你通常想要终止进程,但对于服务来说,这并不是你想要的——如果可以让服务打开一个文件,这本身通常不是好事,但如果可以让服务打开一个管道然后你关闭它,整个服务就会终止。
因此,如果你通过“systemd --user”服务启动 X11 会话的任何相关部分(例如,如果你有一个用于终端仿真器的 .service 或一个用于整个窗口管理器的 .service),服务管理器会将 SIGPIPE 添加到忽略信号集在开始该过程之前,您必须添加IgnoreSIGPIPE=no
以选择退出。
否则,检查你的进程树,直到找到所涉及的最高进程,并在其 /proc/PID/status 中设置了 SIGPIPE 位SigIgn:
;该进程或其父进程可能是原因。