ハドソンでシェルスクリプトを実行する必要があります。そのスクリプトには、ユーザーからの回答が必要です。自動応答を行うために、次のコマンドラインを実行しました。
yes | ./MyScript.sh
これはUbuntuターミナルでうまく機能します。しかし、Hudsonジョブで同じコマンドを使用すると、スクリプトが自動化され、必要なすべての作業が実行されますが、最後に、次の2行のエラーが発生します。
yes: standard output: Broken pipe
yes: write error
そして、これは私のハドソンの仕事に失敗を引き起こします。
ハドソンでうまく機能するようにコマンドラインを変更するにはどうすればよいですか?
しかし、スクリプトの実行中にこのエラーが発生しないことをどのように説明しますかローカル、しかしスクリプトの実行時にエラーが発生しますリモートハドソンの仕事から?
ターミナルで実行している場合(ローカル); yes
は、_MyScript.sh
_がすでに終了しているときにパイプに書き込もうとしたときに生成されるSIGPIPE
シグナルによって強制終了されます。
ハドソンでコマンド(remotely)を実行するものは何でも、そのシグナルをトラップします(ハンドラーを_SIG_IGN
_に設定します。trap
コマンドを実行して検索することで、テストできます。出力のSIGPIPEの場合)、新しい子プロセス(yes
および_MyScript.sh
_を実行するもの(この場合はsh
など)のシグナルを復元しません)。シグナルの代わりに書き込みエラー(EPIPE
)が発生します。 yes
は書き込みエラーを検出し、報告します。
エラーメッセージは無視してかまいません。
_yes 2>/dev/null | ./MyScript.sh
_
パイプラインを実行するコンポーネントに対するバグを報告することもできます。バグは、子がフォークされた後、SIGPIPEをデフォルトのハンドラーに復元しないことです。これは、プログラムがPOSIXシステムの端末で実行されるときに期待するものです。 Javaベースのプログラムでそれを行う標準的な方法があるかどうかはわかりませんが。 jvm
はおそらくすべての書き込みエラーに対して例外を発生させるので、SIGPIPEで死なないことはJavaプログラムにとって問題ではありません。
ハドソンプロセスなどのデーモンがSIGPIPEシグナルを無視することは一般的です。通信しているプロセスが停止し、とにかく書き込みエラーをチェックするという理由だけでデーモンが停止することは望ましくありません。
ターミナルで実行するように作成された通常のプログラムは、すべてのprintf()
のステータスでエラーをチェックしませんが、パイプラインのプログラムが停止した場合、たとえば_source | sink
_パイプラインを実行した場合にそれらを停止させます。通常、source
が終了した場合、sink
プロセスをできるだけ早く終了する必要があります。
EPIPE
シグナルが無効になっている場合(ハドソンの場合のように)、またはプログラムがそれを受信しても停止しない場合(SIGPIPE
プログラムが定義されていない場合)、yes
書き込みエラーが返されます。 SIGPIPE
のハンドラーなので、シグナルを受信すると停止するはずです)。
エラーを無視したくありません。正しいコマンドを実行するか、エラーを取り除くために修正したいと思います。
唯一の方法 yes
プロセスは、強制終了されるか、書き込みエラーが発生すると停止します 。 SIGPIPE
シグナルが(親によって)無視されるように設定されていて、他のシグナルがプロセスを強制終了しない場合、yes
は_./MyScript.sh
_終了時に書き込みエラーを受け取ります。 yes
プログラムを使用する場合、他のオプションはありません。
SIGPIPE
シグナルとEPIPE
エラーは、まったく同じ情報を伝達します-パイプが壊れています。 SIGPIPE
がyes
プロセスに対して有効になっている場合、エラーは表示されません。そして、あなたがそれを見たという理由だけで。新しいことは何も起こりません。これは、_./MyScript.sh
_が終了したことを意味します(成功または失敗-問題ではありません)。
Yesプログラムを使用してスクリプトにパイプしようとしていますか?またはスクリプトにyesをエコーしますか?プロセスがjenkinsを介して機能している場合は、シェルコマンドの最後に「; true」を追加します。
yes
と./MyScript.sh
はそれぞれ明示的なサブシェルで実行できるため、yes
コマンドをバックグラウンドで実行し、yespid
を./MyScript.sh
に送信することができます。サブシェルを作成し、そこにEXIT
にトラップを実装して、yes
コマンドを手動で終了します。 (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[*]}
)
終了コード0
でyes
サブシェルを終了する場合は、次のようにすることもできます。
# 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[*]}
)
このエラーが発生しましたが、問題はyes: standard output: Broken pipe
を出力することではなく、エラーコードを返すことです。
スクリプトを bash strict mode include -o pipefail
で実行しているため、「エラー」が発生すると、スクリプトでエラーが発生します。
私がこれを避けた方法は次のようなものです:
bash -c "yes || true" | my-script.sh