【问题标题】:Is there a workaround for this Broken Pipe error?这个断管错误有解决方法吗?
【发布时间】:2018-02-10 21:43:31
【问题描述】:

当我运行以下脚本时:

#!/bin/bash
cat /dev/urandom | tr -dc '[:graph:]' | head -c 64

(它应该打印 64 个随机字符,并且确实如此)

我得到以下输出:

Kn5Thh'H]F2NMG3^2(T*GdH]C+|Y0uj%C?LGFo=9d9o%vcP9k~6u~Q&exr`RuQv{./myScript: line 2: 21677 Broken Pipe             cat /dev/urandom
     21678                       | tr -dc '[:graph:]'
     21679 Done                    | head -c 64

为什么我会收到 Broken Pipe 错误?是不是因为cat没有完成打印但是head已经完成了,所以它发送了SIGPIPE

如何避免这种情况?

【问题讨论】:

标签: bash pipe


【解决方案1】:

嗯,这种行为似乎取决于两个设置:

  1. 编译时选项 DONT_REPORT_SIGPIPE 尚未在您的 bash 版本中设置 (cf config-top.h)
  2. bash 选项 set -o pipefail 在您的环境中生效

不过,你可以创建一个带括号的子shell,并将子shell的标准错误重定向到/dev/null:

(tr -dc '[[:graph:]]' </dev/urandom | head -c64) 2>/dev/null

--- 在最后一次编辑之前,这个答案看起来像这样:---

tr -dc '[[:graph:]]' </dev/urandom 2>/dev/null | head -c64

【讨论】:

  • 我有点怀疑,但编辑了我的答案并添加了另一个版本。
  • 好的,检查了问题,您似乎有两个不寻常(但完全有效/合法)的设置生效。
【解决方案2】:

您实际上不需要pipe,也不需要使用cat 来打印/dev/urandom 的输出,这是一个非常糟糕的习惯,会产生不必要的进程和浪费循环。

以下命令可以正常工作(bash):

head -c64 <(tr -dc '[[:graph:]]' < /dev/urandom)

输出:

$ head -c64 <(tr -dc '[[:graph:]]' < /dev/urandom)
\|_)gk$,gIW%vvBcc~B~:N2*FwozcdomgUI~I9$r$9Wj`q$KT4IoNI`)SS-i"Sc^

$ head -c64 <(tr -dc '[[:graph:]]' < /dev/urandom)                                                                                             
T8j0,?L))L4n@|(*EJ>Nkd|c7^t'[-7rnq8;E!sxIc>;SwOIhiPY"Zp}QWH&95nC

阅读材料:

https://www.ibm.com/developerworks/aix/library/au-badunixhabits.html#ten https://www.infoworld.com/article/2614499/unix/unix--when-pipes-don-t-make-sense.html https://superuser.com/questions/1059781/what-exactly-is-in-bash-and-in-zsh http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-3.html

对于其他外壳使用:

tr -dc '[[:graph:]]' </dev/urandom | head -c64

【讨论】:

  • 如何使用非 bash-only 变体:tr -dc '[[:graph:]]' &lt;/dev/urandom | head -c64
  • 感谢您的洞察!!! :) 我已经编辑了帖子以考虑其他外壳
  • 谢谢,我没有意识到我可以完全放弃cat...但是,使用head -c64 &lt;(tr -dc '[:graph:]' &lt; /dev/urandom) 仍然会导致Broken Pipe 错误...
【解决方案3】:

您对问题原因的诊断是正确的,一种简单的解决方法是使用 sed 而不是 head:sed -n "1,10p" 等效于 head -n10。或者在您的特定情况下,这将匹配并打印标准输入中的前 64 个字符:

sed -rn "1s/(.{64}).*/\1/p"

-r 是一个 Gnu 扩展。没有它,它看起来更复杂,但这只是因为特殊字符必须被转义:

sed -n "1s/\(.\{64\}\).*/\1/p"

不同的系统可能需要不同的引号字符,例如' 而不是 ".

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-11
    • 2011-11-03
    • 2012-03-13
    • 1970-01-01
    相关资源
    最近更新 更多