哈德森:“是的:标准输出:断管”

Posted

技术标签:

【中文标题】哈德森:“是的:标准输出:断管”【英文标题】:Hudson : "yes: standard output: Broken pipe" 【发布时间】:2014-01-01 14:55:46 【问题描述】:

我需要在 hudson 中运行一个 shell 脚本。该脚本需要用户的回答。为了给出自动答案,我执行了以下命令行:  

yes | ./MyScript.sh

这在 Ubuntu 终端中运行良好。但是当我在 Hudson 作业中使用相同的命令时,脚本将自动完成所有需要的工作,但最后,我得到这两行错误:

yes: standard output: Broken pipe
yes: write error

这会导致我的 Hudson 工作失败。

我应该如何更改我的命令行以在 Hudson 中正常工作?

【问题讨论】:

【参考方案1】:

我遇到了这个错误,我的问题不是它输出yes: standard output: Broken pipe,而是它返回一个错误代码。

因为我使用bash strict mode (包括-o pipefail)运行我的脚本,所以当是“错误”时,它会导致我的脚本出错。

如何避免错误

我避免这种情况的方式是这样的:

bash -c "yes || true" | my-script.sh

【讨论】:

【参考方案2】:

由于yes./MyScript.sh 都可以在显式子shell 中运行,因此可以将yes 命令置于后台,将yespid 发送到./MyScript.sh 子shell,然后在EXIT 上执行陷阱在那里手动终止yes 命令。 (EXIT 上的陷阱应始终在管道命令序列的最后一个命令的子 shell 中实现。

# avoid hangup or "broken pipe" error message when parent process set SIGPIPE to be ignored
# sleep 0 or cat /dev/null: do nothing but with external command (for a shell builtin command see: help :)
(
trap "" PIPE
( (sleep 0; exec yes) & echo $!; wait $! ) | 
   ( 
     trap 'trap - EXIT; kill "$yespid"; exit 0' EXIT
     yespid="$(head -n 1)"
     head -n 10  # replacement for ./MyScript.sh
   )
echo $PIPESTATUS[*]
)

如果您想使用退出代码0 退出yes 子shell,您也可以这样做:

# avoid hangup or "broken pipe" error message when parent process set SIGPIPE to be ignored
# set exit code of yes subshell to 0
(
trap "" PIPE
   (
      trap 'trap - TERM; echo "kill from yes subshell ..." 1>&2; kill "$!"; exit 0' TERM 
      subshell_pid="$(bash -c 'echo "$PPID"')"
      (sleep 0; exec yes) & echo "$subshell_pid"; wait $! 
   ) | 
   ( 
      trap 'trap - EXIT; kill -s TERM "$subshell_pid"; exit' EXIT
      subshell_pid="$(head -n 1)"
      head -n 10  # replacement for ./MyScript.sh
   )
echo $PIPESTATUS[*]
)

【讨论】:

尤其是后一个脚本看起来过于复杂。您可以在第一个中使用wait $! || : 使退出状态为0。使用read -r yespid 比使用yespid="$(head -n 1)" 更好。当您在yes 之前有sleep 0 时,您能确定pid 首先写入管道吗? yes 没有问题,但一般情况下,如果管道左侧先退出,您应该隐藏 kill 可能出现的错误。 在我的answer 的相关问题中,我解决了我上面提到的问题。【参考方案3】:

命令是在无限循环中运行,我认为这可能是解决方案:

yes | head -1 | ./MyScript.sh #only one "Y" would be output of the command yes

但是,我遇到了同样的错误。

我们可以按照@J.F. 的建议将错误重定向到 /dev/null。塞巴斯蒂安,或者通过这个来强制命令是正确的:

yes | head -1 | ./MyScript.sh || yes

但是,这些建议不太受欢迎。因此,我必须创建自己的命名管道,如下所示:

mkfifo /tmp/my_fifo #to create the named pipe
exec 3<>/tmp/my_fifo #to make the named pipe in read and write mode by assigning it to a file descriptor
echo "Y" >/tmp/my_fifo #to write into the named pipe, "Y" is the default value of yes
./MyScript.sh </tmp/my_fifo #to read from the named pipe
rm /tmp/my_fifo #remove the named pipe

我期待更多有价值的解决方案和更多解释。

Here是对linux中文件描述符的解释。

谢谢

【讨论】:

第一个命令应该产生同样的错误。如果你不明白; my answer 失败。如果./MyScript.sh 失败,第二个命令将再次启动yes。你为什么要这样做? (请记住,管道的退出代码是 last 命令的退出代码(yes | cmd 为您提供 cmd 的退出状态,无论 yes 的退出状态如何)。 第三组命令(使用 mkfifo)是写 echo "Y" | ./MyScript.sh; true 的一种变态方式它只产生 一个 "Y"yes 的默认值是无限的 根据需要 "y"(小写))并且它隐藏退出状态./MyScript.sh。如果./MyScript.sh 一个“Y”就足够了,那么使用echo Y | ./MyScript.sh【参考方案4】:

但是您如何解释我在本地运行脚本时没有收到此错误,但在 Hudson 作业中远程运行它时却收到了错误?

当您在终端中运行它时(本地); yesSIGPIPE 信号杀死,该信号是在MyScript.sh 已经退出时尝试写入管道时生成的。

无论在 Hudson 中运行命令 (remotely) 的什么都会捕获该信号(将其处理程序设置为 SIG_IGN,您可以通过运行 trap 命令并在输出中搜索 SIGPIPE 来测试它)和它不会恢复新子进程的信号(yes 和运行MyScript.sh 的任何东西,例如,sh 在你的情况下)。它会导致写入错误 (EPIPE) 而不是信号。 yes 检测到写入错误并报告。

你可以直接忽略错误信息:

yes 2>/dev/null | ./MyScript.sh

您还可以针对运行管道的组件报告错误。错误在于在孩子分叉后没有将 SIGPIPE 恢复到默认处理程序。这是程序在 POSIX 系统的终端中运行时所期望的。虽然我不知道对于基于 java 的程序是否有标准的方法。 jvm 可能会为每个写入错误引发异常,因此在 SIGPIPE 上不死对 java 程序来说不是问题。

守护进程(例如 hudson 进程)忽略 SIGPIPE 信号是很常见的。你不希望你的守护进程死掉,因为你正在与之通信的进程死了,无论如何你都会检查写入错误。

编写为在终端中运行的普通程序不会检查每个 printf() 的状态是否有错误,但如果管道中的程序死亡,例如,如果您运行 source | sink 管道,您希望它们死亡;通常,如果sink 退出,您希望source 进程尽快退出。

EPIPE 如果SIGPIPE 信号被禁用(就像在 hudson 的情况下一样)或者如果程序在接收它时没有死掉(yes 程序没有为SIGPIPE 定义任何处理程序,则返回写入错误所以它应该在收到信号时死掉)。

我不想忽略错误,我想做正确的命令或修复以消除错误。

唯一的yes process stops if it is killed or encountered a write error。如果SIGPIPE 信号设置为被忽略(由父级)并且没有其他信号终止进程,则yes./MyScript.sh 退出时收到写入错误。如果您使用yes 程序,则没有其他选项。

SIGPIPE 信号和EPIPE 错误传达完全相同的信息——管道已损坏。如果为yes 进程启用了SIGPIPE,那么您将看不到错误。只是因为你看到了它;没有新的事情发生。这只是意味着 ./MyScript.sh 退出(成功或不成功 - 无关紧要)。

【讨论】:

您好,感谢您提出的解决方案。但我担心这个解决方案可能会将任何错误重定向到 /deb/null (损坏的管道或其他)。所以,我宁愿需要一个解决问题的命令。谢谢 @Farah:如果您不想忽略错误。如果你检测到一个,你想用它做什么? 我同意您刚刚所做的修改,+1。但是您如何解释我在本地运行脚本时没有收到此错误,但从 Hudson 作业远程运行时却收到错误? @Farah:你的最后一个问题是我从一开始就试图解释的答案。 谢谢您,很好地解释了正在发生的事情。你应该得到赏金。【参考方案5】:

您正在尝试使用 yes 程序来管道到脚本?或对脚本回显是?如果进程通过 jenkins 运行,请在 shell 命令的末尾添加“; true”。

【讨论】:

您好,谢谢您的建议。但我不应该忽视这个例外。

以上是关于哈德森:“是的:标准输出:断管”的主要内容,如果未能解决你的问题,请参考以下文章

swiftUI 2.0列表滚动很慢,我找不到原因..即使是保罗哈德森的伎俩也不起作用

接口测试

R安德森-达令检验( Anderson-Darling Test)

解释安德森亲爱的测试 scipy

Ruby | 拒绝寡淡——韦斯·安德森电影中教科书般的配色哲学

Hudson、windows2008和git插件