管道破裂,写入错误:不必要输出泛滥

管道破裂,写入错误:不必要输出泛滥

在过去的几个月里,我的系统出现了一个问题。那就是管道损坏错误:

# 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% 的计算机使用都是通过终端进行的,这种垃圾邮件是非常不受欢迎的。

我正在努力思考解决方案:

  1. 替换实现,bzip2-referencelbzip2
  2. 更换用法,headawk 'NR<11'
    • 我不同意,断开管道听起来是个合理的做法。如果标准输入是 GiB?TiB?无限?curl?串行?怎么办?
  3. 添加2>/dev/null到每个管道命令中。你知道为什么这是一个坏主意。
  4. 降级软件包。我不能再这样做了。无论如何我都想保持最新状态。
  5. 添加补丁/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:;该进程或其父进程可能是原因。

相关内容