すべてのエラーの関数を呼び出すためにトラップを使用していくつかのエラーレポートを作成しようとしています。
Trap "_func" ERR
ERR信号が送信されるラインを取得できますか?シェルはbashです。
これにより、どのコマンドが使用されたかを読み、報告したり、一部の操作を記録/実行したりできます。
それとも私が間違っているのでしょうか?
私は以下をテストしました。
#!/bin/bash
trap "ECHO $LINENO" ERR
echo hello | grep "asdf"
2を返してい$LINENO
ます。動作しません。
答え1
コメントで指摘したように、あなたの見積もりが間違っています。$LINENO
初めて解析するときにトラップ行が拡大するのを防ぐには、単一引用符が必要です。
これは働きます:
#! /bin/bash
err_report() {
echo "Error on line $1"
}
trap 'err_report $LINENO' ERR
echo hello | grep foo # This is line number 9
実行してください:
$ ./test.sh
Error on line 9
答え2
bash 内蔵の「発信者」も使用できます。
#!/bin/bash
err_report() {
echo "errexit on line $(caller)" >&2
}
trap err_report ERR
echo hello | grep foo
また、ファイル名も印刷します。
$ ./test.sh
errexit on line 9 ./test.sh
答え3
ERR信号が送信されるラインを取得できますか?
はい、LINENO
変数はBASH_LINENO
失敗した行と失敗した行を取得するのに役立ちます。
それとも私が間違っているのでしょうか?
いいえ、ただ抜けました。-q
グレブオプション...
echo hello | grep -q "asdf"
...そして-q
オプションが返されgrep
ます0
true
1
そしてfalse
。バッシュではtrap
いいえTrap
...
trap "_func" ERR
...基本的なソリューションが必要です...
以下は、循環的な複雑さがより大きな問題をデバッグするのに役立ちますトラップです。
## Outputs Front-Mater formatted failures for functions not returning 0
## Use the following line after sourcing this file to set failure trap
## trap 'failure "LINENO" "BASH_LINENO" "${BASH_COMMAND}" "${?}"' ERR
failure(){
local -n _lineno="${1:-LINENO}"
local -n _bash_lineno="${2:-BASH_LINENO}"
local _last_command="${3:-${BASH_COMMAND}}"
local _code="${4:-0}"
## Workaround for read EOF combo tripping traps
if ! ((_code)); then
return "${_code}"
fi
local _last_command_height="$(wc -l <<<"${_last_command}")"
local -a _output_array=()
_output_array+=(
'---'
"lines_history: [${_lineno} ${_bash_lineno[*]}]"
"function_trace: [${FUNCNAME[*]}]"
"exit_code: ${_code}"
)
if [[ "${#BASH_SOURCE[@]}" -gt '1' ]]; then
_output_array+=('source_trace:')
for _item in "${BASH_SOURCE[@]}"; do
_output_array+=(" - ${_item}")
done
else
_output_array+=("source_trace: [${BASH_SOURCE[*]}]")
fi
if [[ "${_last_command_height}" -gt '1' ]]; then
_output_array+=(
'last_command: ->'
"${_last_command}"
)
else
_output_array+=("last_command: ${_last_command}")
fi
_output_array+=('---')
printf '%s\n' "${_output_array[@]}" >&2
exit ${_code}
}
...そして、上記の関数追跡トラップを設定する方法の微妙な違いを示すサンプル使用スクリプト...
#!/usr/bin/env bash
set -E -o functrace
## Optional, but recommended to find true directory this script resides in
__SOURCE__="${BASH_SOURCE[0]}"
while [[ -h "${__SOURCE__}" ]]; do
__SOURCE__="$(find "${__SOURCE__}" -type l -ls | sed -n 's@^.* -> \(.*\)@\1@p')"
done
__DIR__="$(cd -P "$(dirname "${__SOURCE__}")" && pwd)"
## Source module code within this script
source "${__DIR__}/modules/trap-failure/failure.sh"
trap 'failure "LINENO" "BASH_LINENO" "${BASH_COMMAND}" "${?}"' ERR
something_functional() {
_req_arg_one="${1:?something_functional needs two arguments, missing the first already}"
_opt_arg_one="${2:-SPAM}"
_opt_arg_two="${3:0}"
printf 'something_functional: %s %s %s' "${_req_arg_one}" "${_opt_arg_one}" "${_opt_arg_two}"
## Generate an error by calling nothing
"${__DIR__}/nothing.sh"
}
## Ignoring errors prevents trap from being triggered
something_functional || echo "Ignored something_functional returning $?"
if [[ "$(something_functional 'Spam!?')" == '0' ]]; then
printf 'Nothing somehow was something?!\n' >&2 && exit 1
fi
## And generating an error state will cause the trap to _trace_ it
something_functional '' 'spam' 'Jam'
上記のテストは Bash バージョン 4 以降で行われたので、4 以前のバージョンが必要な場合はコメントを残してください。問題を開く最小バージョンが4のシステムでエラーをキャッチできない場合。
基本テイクアウトはい...
set -E -o functrace
-E
関数内でエラーが発生します。泡-o functrace
原因を使用すると、関数内のどの項目が失敗した場合に詳細な情報を取得できます。
trap 'failure "LINENO" "BASH_LINENO" "${BASH_COMMAND}" "${?}"' ERR
関数呼び出しには一重引用符が使用され、個々のパラメーターには二重引用符が使用されます。
参考資料
LINENO
そしてBASH_LINENO
現在の値の代わりに渡されます。ただし、トラップに接続されている以降のバージョンでは短縮され、最終的な障害ラインを出力に含めることができます。価値
BASH_COMMAND
および終了ステータス($?
)が渡されます。最初にエラーを返すコマンドを取得し、2番目にエラーではなくトラップがトリガーされないようにするために渡されます。
他の人は同意しないかもしれませんが、出力配列を作成し、printfを使用して各配列要素を1行に印刷する方が簡単です。
printf '%s\n' "${_output_array[@]}" >&2
...しかも>&2
最後のビットは、エラーが発生する場所(標準エラー)でエラーを発生させ、エラーのみをキャッチすることを可能にします。
## ... to a file...
some_trapped_script.sh 2>some_trapped_errros.log
## ... or by ignoring standard out...
some_trapped_script.sh 1>/dev/null
これらと他の例スタックオーバーフローには、組み込みユーティリティを使用してデバッグサポートを構築する方法がたくさんあります。
答え4
@sanmaiと@unpythonicに触発された別のバージョンがあります。エラー、行番号、終了ステータスの周囲のスクリプト行を表示します。これはawkソリューションよりも単純に見えるので、tailとheadを使用します。
読みやすくするために2行で表示されます。必要に応じて、2行を1つにマージできます(メンテナンス;
)。
trap 'echo >&2 "Error - exited with status $? at line $LINENO:";
pr -tn $0 | tail -n+$((LINENO - 3)) | head -n7 >&2' ERR
これはset -eEuo pipefail
(非公式厳格モード)
- 未定義の変数エラーは、偽信号をトリガーせずに行番号を提供しますが、
ERR
他の場合はコンテキストを表示します。
出力例:
myscript.sh: line 27: blah: command not found
Error - exited with status 127 at line 27:
24 # Do something
25 lines=$(wc -l /etc/passwd)
26 # More stuff
27 blah
28
29 # Check time
30 time=$(date)