Bashのdebugは一つのswitchではありません。bash -nはsyntax、-xは実行trace、-vはreadしたinput line、set -uはunset variable、pipefailはpipeline statusを扱います。set -eは文脈により例外があり、付ければ安全になる万能なstrict modeではありません。
結論は「最初にbash -n、次に無害なsampleでscope限定のset -xを使い、PS4とBASH_XTRACEFDでtraceを分離します。password、token、private dataを扱う区間ではxtraceを無効にします」です。
syntax・trace・statusのdebugを分ける
xtraceはparameter expansion等の後に実行されるcommandを表示するため、source codeに直接書かれていないsecret値もlogへ現れます。PS4はtrace prefix、BASH_XTRACEFDはtrace output descriptorを指定できます。stderrとtraceを分けるとapplication errorを読みやすくなります。
- Bash versionと実行option
- 再現するinputと期待failure point
- traceへ展開されるsecret・path・personal data
- subshell、function、pipelineの境界
- debug終了後にoptionを元へ戻す方法
production dataでいきなりbash -xを使わず、同じstructureのredacted sampleを作ります。bash -nでsyntaxを除外し、shellcheck等のstatic toolを使う場合も対象Bash versionでruntime testを行います。error lineだけでなく直前のinputとstatusを保存します。
Bashのdebug方法を、構文検査のbash -n、入力行表示の-v、展開後command traceの-x、unset variable検出の-u、pipeline失敗を返すpipefailへ分けます。対象Bash版、実行引数、再現する最小入力、期待exit statusを確認し、traceへpassword、token、個人データが出る箇所を先に洗い出します。set -eは文脈依存の例外が多く、万能なstrict modeではありません。
trace範囲を数行へ限定する
script copyでbash -nを行い、problem functionの直前でset -x、直後でset +xにします。PS4へsource、line、functionを入れ、descriptor 19等をpermission限定trace fileへ向けます。failure後にexit statusを直ちに保存し、trace fileを安全に片付けます。
syntaxを検査
bash -n -- ./job.sh
runtime commandを実行せずsyntax errorだけを確認します。
script全体をsample trace
bash -x -- ./job.sh sample-input
secretを含まないtest fixtureだけで使い、production argumentでは実行しません。
scopeを限定
set -x
printf 'item=%s\n' "$item"
set +x
problem箇所だけをtraceし、set +x後にxtraceがoffか確認します。
traceを別fileへ出す
exec 19>./job.trace
BASH_XTRACEFD=19
PS4='+ $BASH_SOURCE:$LINENO:$FUNCNAME: '
set -x
trace fileのmodeと保存先を確認し、終了時にdescriptorをcloseします。
pipeline failureを表面化
set -o pipefail
producer | consumer
rc=$?
printf 'pipeline_exit=%s\n' "$rc"
各commandのfailure意味をtestし、set -e任せでcleanupを飛ばさない設計にします。
まずbash -n — script.shで実行せず構文を検査し、機密を含まないfixtureで問題functionの直前だけset -x、直後にset +xを置きます。PS4へBASH_SOURCE、LINENO、FUNCNAMEを含め、BASH_XTRACEFDで通常stderrとは別の権限制限fileへtraceを送れます。failure直後の$?を別commandで上書きする前に保存し、cleanupの動作も記録します。
PS4・BASH_XTRACEFDとset -e・-u・pipefailを理解する
-xはexpanded command、-vはinput lineを表示します。set -uはunset parameter展開をerrorにしますが、default値やoptional argumentの設計が必要です。pipefailなしではpipeline statusが最後のcommand中心になり、途中failureが隠れます。set -eはconditional、list、subshell等で複雑な規則を持ちます。
- bash -nはcommandを実行せずsyntaxを読む
- xtraceはexpansion後の値を表示するためsecret leakを起こし得る
- PS4でsource・line等のtrace prefixを設定できる
- BASH_XTRACEFDでtraceをstderr以外へ送れる
- pipefailはpipeline内failureのstatus選択を変える
xtraceはparameter expansion等の後に実行commandを表示するため、sourceに直接書かれていない秘密値も展開後に現れます。-vはshellが読む入力行を表示し、-nは多くの構文を検査しますがruntime branchの論理は保証しません。pipefailなしではpipeline全体のstatusが原則最後のcommandに依存し、中間failureを見逃します。set -uと-eはconditionalやsubshellで挙動をtestする必要があります。
secretをtraceへ出さない設計
xtrace logへcredential、authorization header、customer dataを出しません。既に漏れた場合はlog削除だけでなくsecret rotationとaccess reviewを行います。productionで常時debugを有効化せず、trace fileへ0600相当のpermission、retention、ownerを設定します。
- set -xをscript全体へ付けてsecretを出す
- bash -n成功をlogic保証とする
- set -eをtry/catchの代わりに考える
- pipeline途中failureを見ない
- debug optionをoffへ戻さず次処理へ渡す
productionでscript全体のbash -xを無期限に有効化しません。Authorization header、database URL、個人データを扱う区間ではxtraceを明示的にoffにし、既に漏れた場合はログ削除だけでなくcredential rotationとaccess reviewを行います。trace fileは0600相当、限定owner、短い保持期間にし、CI artifactや一般ログ収集へ自動uploadされないよう設定します。
failure caseを含めてtestする
正常、unset variable、pipeline途中failure、subshell、function return、cleanup pathをfixtureでtestします。stdout、stderr、trace、exit statusを別々に確認し、traceに模擬secretが露出する場所を修正します。終了後case $-でxtraceがoffか確認します。
- syntax errorとruntime errorを別に調べた
- trace範囲と出力先を最小化した
- secretを含まないfixtureでfailureを再現した
- option状態・exit status・cleanupをtestした
正常、unset variable、pipeline中間failure、command substitution、subshell、function return、signal、cleanupを含むfixtureを実行し、stdout、stderr、trace、exit statusを別々に比較します。PS4のsource/lineが実際のfailure箇所を指すか、set +x後に秘密の模擬値が出ないかを確認します。修正後はdebug optionなしの通常実行で同じ結果になり、case $-にxが残らないことを確認します。
症状に合うdebug方法を選ぶ
syntaxなら-n、flowなら-x、pipelineならpipefail/status、dataならassert/validationを使います。productionでしか再現しない場合は、値をmaskしたstructured logや一時的なfeature flagを設計し、無差別xtraceを避けます。
構文なら-n、制御flowなら限定-x、pipelineならpipefailと各status、data妥当性ならassertionやvalidationを選びます。複雑なerror propagationをset -eへ委ねず、重要commandごとに明示的なifとerror処理を記述します。productionでしか再現しない場合は、値をmaskしたstructured logや短時間のfeature flagを設計し、全量xtraceを常態化しません。

コメント