散発的な 141 シェル スクリプト エラーのデバッグ

散発的な 141 シェル スクリプト エラーのデバッグ

CI (Gitlab、Alpine Linux を実行する Docker コンテナ) でスクリプトを実行しているときに、シグナル 141 で散発的にエラーが発生します。これは「SIGPIPE」を示しているようです。しかし、どのステップが失敗しているのか、またはデバッグするにはどうすればよいのかわかりません。

  #!/usr/bin/env bash

  set -euxo pipefail
  set -a

  # ...
  git fetch --tags 

  RELEASE=$(git tag | grep -E "${BUILD_ENV}-release-(\d+)" | cut -d"-" -f3 | sort -nr | head -1)
  RELEASE=$(( RELEASE + 1 ))

散発的なエラーはパイプ内の最後から 2 番目の行で発生するようです。取得したログは次のとおりです。

++ git tag
++ cut -d- -f3
++ sort -nr
++ grep -E 'prod-release-(\d+)'
++ head -1
+ RELEASE=323
ERROR: Job failed: exit code 141

実際に失敗した行を特定するには、これをデバッグするにはどうすればよいでしょうか? RELEASE 変数は正常に設定されたようですが、その後何らかの理由でエラーが発生したようです。

答え1

head -1ジョブが完了したら、sort -nrすべてのデータをパイプに書き込んだかどうかに関係なく終了します。sort書き込むべきデータがまだ残っていて、headそれ以上書き込めない場合は、sortを取得しますSIGPIPE

何も起こりません。これがパイプの仕組みです。headをパイプで使用する場合、 が原因で前のコマンドが終了しても驚かないでくださいSIGPIPE


yesの代わりに を使用した簡単なテストsort:

$ set -o pipefail
$ yes | head -n 1
y
$ printf '%s\n' "$?" "${PIPESTATUS[@]}"
141             <- overall exit status
141             <- from `yes'
0               <- from `head'

終了ステータスは であり141、 から取得されますyes

これは、 を調べてデバッグする方法を示しています${PIPESTATUS[@]}


この動作は想定どおりです。パイプのこの部分の終了ステータスを操作するには、の代わりにyes(または、この場合は の代わりに)サブシェルを使用します。例:sort

$ set -o pipefail
$ (yes; true) | head -n 1
y
$ printf '%s\n' "$?" "${PIPESTATUS[@]}"
0
0
0

のみを抑制するより複雑なロジック141:

(yes; e="$?"; [ "$e" -eq 141 ] && exit 0; exit "$e") | head -n 1

関連情報