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

时间:2013-12-13 18:16:56

标签: shell ubuntu jenkins hudson pipe

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

yes | ./MyScript.sh

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

yes: standard output: Broken pipe
yes: write error

这导致我的哈德森工作失败。

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

5 个答案:

答案 0 :(得分:25)

  

但是你如何解释我在运行脚本本地时没有收到此错误,但是从Hudson作业中远程运行远程时出现错误?

在终端(本地)中运行时; yesSIGPIPE退出时尝试写入管道时生成的MyScript.sh信号被SIG_IGN信号杀死。

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

您可以忽略错误消息:

jvm

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

hudson进程等守护进程通常忽略SIGPIPE信号。您不希望您的守护程序死亡只是因为您正在与之通信的进程终止而且您无论如何都会检查写入错误。

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

如果SIGPIPE信号被禁用(在hudson的情况下看起来像),或者程序在接收时没有死亡,则返回

yes写入错误(SIGPIPE程序未定义SIGPIPE的任何处理程序,因此它应该在收到信号时死亡。

  

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

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

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

答案 1 :(得分:1)

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

答案 2 :(得分:0)

由于yes./MyScript.sh都可以在显式子shell中运行,因此可以对yes命令进行后台处理,将yespid发送到./MyScript.sh subshel​​l然后在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[*]}
)

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

# 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[*]}
)

答案 3 :(得分:0)

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

因为我使用bash strict mode运行我的脚本,包括-o pipefail,如果是“错误”,则会导致我的脚本出错。

如何避免错误

我避免这种情况的方式如下:

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

答案 4 :(得分:-1)

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

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中文件描述符的解释。

由于