このスクリプトがあります。
#!/bin/bash
# -> dump.$pid
ulimit -c unlimited
# trap ERR
set -o errexit
# also trap error in the middle of a pipe (1)
# otherwise it will only trap the error on (2)
set -o pipefail
trap 'echo "ERR $?"' ERR
echo "a"
echo "1" | ./crash | cat
echo "b"
echo "2" | ./crash
echo "c"
期待どおりに動作します。
$ ./script.sh >& script.log
$ echo "$?"
139
$ cat script.log
a
Segmentation fault (core dumped)
ERR 139
(pipefail
存在しない場合は「ab」が印刷され、存在しない場合はerrexit
「ab c」が印刷されます)
ただし、これは大きなパイプラインの一部であり、バッチシステムで実行されるため、競合が発生する可能性があり、ファイルに十分なargv
情報がありませんdump.?????
。
それでは、スクリプトエラーを発生させたプロセスのPID(および予想されるコアダンプファイル名)を他のすべてのプロセスで記録できるようにどのように印刷しますか?
競合するプログラムは、より大きなパイプラインの一部である可能性があります(特にパイプの末尾に常にあるわけではないので、使用しますpipefail
)。すべての呼び出しをラッパーコードで囲んだりできない状況を避けたいです。プログラム間で直接データを転送します。
ベストアンサー1
SIGSEGV
ジョブ制御を有効にすると問題が解決することがわかりました。ただし、詳細な出力を防ぐトラップや設定がない場合にのみ可能です。
set -o errexit
set -o pipefail
set -o monitor
trap 'echo "ERR $?"' ERR
echo "hi" | ./docrash | cat
echo "not reached"
これを実行すると、私が探している結果とそれ以上を正確に得ることができます。各サブプロセスのPIDを印刷し、エラーを表示します。
$ ./err.sh >& err.log
$ cat err.log
./err.sh: line 21: 25110 Done echo "hi"
25111 Segmentation fault (core dumped) | ./docrash
25112 | cat
ERR 139
$ gdb docrash core.25111
...
パイプラインの障害を確認してもスクリプトを中断したくない場合は、次の設定を組み合わせることができます。
set -o pipefail
set -o monitor
echo "hi" | ./docrash | cat
echo "pipe returned $?"
トレースを印刷して続行します。
$ ./err.sh
./err.sh: line 21: 25110 Done echo "hi"
25111 Segmentation fault (core dumped) | ./docrash
25112 | cat
pipe returned 139