哈德森:“是的:标准输出:断管”
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 作业中远程运行它时却收到了错误?
当您在终端中运行它时(本地); yes
被SIGPIPE
信号杀死,该信号是在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)