我需要在Hudson中运行一个shell脚本。该脚本需要用户提供答案。为了给出自动答案,我执行了以下命令行:
yes | ./MyScript.sh
在Ubuntu终端中这个命令很好用。但当我在Hudson工作时使用同样的命令,脚本会自动化并完成所有所需工作,但最后我会得到这两行错误:
yes: standard output: Broken pipe
yes: write error
这导致了我的Hudson工作失败。
我应该如何更改命令行,使其在Hudson中正常工作?
yes 2>/dev/null | ./MyScript.sh
jvm
可能会为每个写入错误引发异常,因此在SIGPIPE上不死亡对于Java程序来说不是问题。printf()
的错误状态,但如果管道中的程序死亡,您希望它们能够退出,例如,如果您运行source | sink
管道;通常情况下,如果退出,则希望SIGPIPE
signal is disabled (as it looks like in Hudson's case) or if a program does not die on receiving it (yes
program does not define any handlers for SIGPIPE
so it should die on receiving the signal), EPIPE
write error is returned. The goal is to find the right command or fix to get rid of the error, not to ignore it. The only way yes
process stops if it is killed or encountered a write error. If SIGPIPE
signal is set to be ignored (by the parent) and no other signal kills the process, then yes
receives write error on ./MyScript.sh
exit. There are no other options if you use yes
program. Please keep the HTML tags and make the content more understandable.
SIGPIPE
信号和EPIPE
错误传达了完全相同的信息——管道已断开连接。如果SIGPIPE
对yes
进程启用,则不会看到错误。仅因为您看到它,没有发生任何新的事情。这意味着./MyScript.sh
已退出(成功或不成功——无关紧要)。-o pipefail
,当yes“出错”时,会导致我的脚本出错。
bash -c "yes || true" | my-script.sh
由于yes
和./MyScript.sh
都可以在显式子shell中运行,因此可以将yes
命令放入后台,将yespid
发送到./MyScript.sh
子shell中,然后在那里实现对EXIT
的陷阱以手动终止yes
命令。(对于管道命令序列的最后一个命令的子shell,应始终实现对EXIT
的陷阱)。
# 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[*]}
)
# 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)"
。当你在 sleep 0
之前有 yes
时,你能确定 pid 是首先写入管道的吗?这不是 yes
的问题,但在一般情况下,如果管道的左侧先退出,则应该隐藏可能的 kill
错误。 - jarno由于命令yes在无限循环中运行,我认为这可能是解决方案:
yes | head -1 | ./MyScript.sh #only one "Y" would be output of the command yes
但是,我得到了相同的错误。
我们可以像@J.F. Sebastian建议的那样将错误重定向到/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
我期待更有价值、更详细的解决方案。
这里是一个关于 Linux 文件描述符的解释。
谢谢。
./MyScript.sh
失败,第二条命令会再次启动yes
。为什么要这样做?(请记住,管道的退出代码是最后一个命令的退出代码(yes | cmd
给出cmd
的退出状态,无论yes
的退出状态如何)。) - jfsecho "Y" | ./MyScript.sh; true
。它只产生一个 "Y"
(因为 yes
的默认值是无限的,即尽可能多的小写字母 "y"
),并且它隐藏了 ./MyScript.sh
的退出状态。如果 ./MyScript.sh
只需要一个 "Y",那么请使用 echo Y | ./MyScript.sh
。 - jfs