Linuxのシェルスクリプトデバッグモードの有効化と応用例

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か確認します。

  1. syntax errorとruntime errorを別に調べた
  2. trace範囲と出力先を最小化した
  3. secretを含まないfixtureでfailureを再現した
  4. 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を常態化しません。

公式情報・参考資料

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次