- 本記載内容は以下内容を自分用にまとめたものになります
bashデバッグTips
モチベーション
- デバッグしやすくしたい
1. Bashオプション(bash -uvx
)
- 動作確認用スクリプト
#!/bin/bash
: [DEBUG] set param
readonly SCORE_ARRAY=(100 90 80 70)
readonly COUNTS=${#SCORE_ARRAY[@]}
function cal_score_ave() {
local _score_sum=i
: [DEBUG] cal
for _score in ${SCORE_ARRAY[@]}
do
_score_sum=$((_score_sum + _score))
done
score_ave=$((_score_sum / COUNTS))
return 0
}
: [DEBUG] main
cal_score_ave
echo $score_ave
echo $param
echo "finished"
exit 0
# bash -uvx cal_score_ave.sh
#!/bin/bash
: [DEBUG] set param
+ : '[DEBUG]' set param
readonly SCORE_ARRAY=(100 90 80 70)
+ SCORE_ARRAY=(100 90 80 70)
+ readonly SCORE_ARRAY
readonly COUNTS=${#SCORE_ARRAY[@]}
+ readonly COUNTS=4
+ COUNTS=4
function cal_score_ave() {
local _score_sum=i
: [DEBUG] cal
for _score in ${SCORE_ARRAY[@]}
do
_score_sum=$((_score_sum + _score))
done
score_ave=$((_score_sum / COUNTS))
return 0
}
: [DEBUG] main
+ : '[DEBUG]' main
cal_score_ave
+ cal_score_ave
+ local _score_sum=i
+ : '[DEBUG]' cal
+ for _score in '${SCORE_ARRAY[@]}'
cal_score_ave.sh: line 12: i: 展開されていない変数
オプション | 説明 |
---|---|
-u | 未定義の変数をチェックしそこで処理を終了する |
-v | 実行するコマンドをそのまま表示する |
-x | 実行内容をトレースする |
1.1 bash -u
# bash -u cal_score_ave.sh
cal_score_ave.sh: line 12: i: 展開されていない変数
1.2 bash -v
# bash -v cal_score_ave.sh
#!/bin/bash
: [DEBUG] set param
readonly SCORE_ARRAY=(100 90 80 70)
readonly COUNTS=${#SCORE_ARRAY[@]}
function cal_score_ave() {
local _score_sum=i
: [DEBUG] cal
for _score in ${SCORE_ARRAY[@]}
do
_score_sum=$((_score_sum + _score))
done
score_ave=$((_score_sum / COUNTS))
return 0
}
: [DEBUG] main
cal_score_ave
echo $score_ave
85
echo $param
echo "finished"
finished
exit 0
1.3 bash -x
# bash -x cal_score_age.sh
+ : '[DEBUG]' set param
+ SCORE_ARRAY=(100 90 80 70)
+ readonly SCORE_ARRAY
+ readonly COUNTS=4
+ COUNTS=4
+ : '[DEBUG]' main
+ cal_score_ave
+ local _score_sum=i
+ : '[DEBUG]' cal
+ for _score in '${SCORE_ARRAY[@]}'
+ _score_sum=100
+ for _score in '${SCORE_ARRAY[@]}'
+ _score_sum=190
+ for _score in '${SCORE_ARRAY[@]}'
+ _score_sum=270
+ for _score in '${SCORE_ARRAY[@]}'
+ _score_sum=340
+ score_ave=85
+ return 0
+ echo 85
85
+ echo
+ echo finished
finished
+ exit 0
2. ヌルコマンド(:
)
: [arguments]
何もしません。
このコマンドはargumentsを展開し、指定されたリダイレクトを実行する以外には何も行いません。
終了コード 0 を返します。
man bash より引用
3. デバッグプロンプト(PS4
)
PS4
このパラメータは PS1 と同じように展開されます。
この値は実行トレース中に bash が表示する各コマンド前に出力されます。
複数段の間接レベル (levels of indirection) を示すときは、
PS4 の最初の文字が必要に応じて複数回表示されます。
デフォルト値は ‘‘+ ’’ です。
man bash より引用
- PS4の変更
-
~/.bashrc
に以下1行追加
-
export PS4='+ (${BASH_SOURCE}:${LINENO}): ${FUNCNAME:+$FUNCNAME(): }'
# bash -x ./cal_score_ave.sh
+ (./cal_score_ave.sh:3): : '[DEBUG]' set param
+ (./cal_score_ave.sh:4): SCORE_ARRAY=(100 90 80 70)
+ (./cal_score_ave.sh:4): readonly SCORE_ARRAY
+ (./cal_score_ave.sh:5): readonly COUNTS=4
+ (./cal_score_ave.sh:5): COUNTS=4
+ (./cal_score_ave.sh:19): : '[DEBUG]' main
+ (./cal_score_ave.sh:20): cal_score_ave
+ (./cal_score_ave.sh:8): cal_score_ave(): local _score_sum=i
+ (./cal_score_ave.sh:9): cal_score_ave(): : '[DEBUG]' cal
+ (./cal_score_ave.sh:10): cal_score_ave(): for _score in '${SCORE_ARRAY[@]}'
+ (./cal_score_ave.sh:12): cal_score_ave(): _score_sum=100
+ (./cal_score_ave.sh:10): cal_score_ave(): for _score in '${SCORE_ARRAY[@]}'
+ (./cal_score_ave.sh:12): cal_score_ave(): _score_sum=190
+ (./cal_score_ave.sh:10): cal_score_ave(): for _score in '${SCORE_ARRAY[@]}'
+ (./cal_score_ave.sh:12): cal_score_ave(): _score_sum=270
+ (./cal_score_ave.sh:10): cal_score_ave(): for _score in '${SCORE_ARRAY[@]}'
+ (./cal_score_ave.sh:12): cal_score_ave(): _score_sum=340
+ (./cal_score_ave.sh:15): cal_score_ave(): score_ave=85
+ (./cal_score_ave.sh:16): cal_score_ave(): return 0
+ (./cal_score_ave.sh:21): echo 85
85
+ (./cal_score_ave.sh:22): echo
+ (./cal_score_ave.sh:23): echo finished
finished
+ (./cal_score_ave.sh:25): exit 0
4. trapコマンド
sigspec | タイミング |
---|---|
EXIT | シェルがスクリプトを終了した |
ERR | コマンド、シェル関数から0以外の終了ステータスが返された |
DEBUG | シェルが各コマンド、算術、シェル関数の最初のコマンドの実行前 |
RETURN | source または . で実行されたシェル関数/スクリプトが終了した |
trap [-lp] [[arg] sigspec ...]
シェルがシグナル sigspec を受け取ると、コマンド arg が読み込まれて、実行されます。
arg が存在しない (かつ sigspec が一つ指定された) 場合か、 arg が - の場合、
指定されたシグナルは全てオリジナルの動作 (シェルの起動時に設定されていた値) にリセットされます。
arg が空文字列である場合、
それぞれの sigspec で指定されたシグナルは、 シェルとシェルが起動したコマンドから無視されます。
arg なしで -p オプションが与えられた場合、
各 sigspec に関連付けられた trap コマンドが表示されます。
引き数が全くないか、 -p だけが与えられた場合、
trap は各シグナルに関連付けられたコマンドのリストを出力します。
-l オプションを与えると、 シェルはシグナル名と対応する番号のリストを出力します。
それぞれの sigspec は、 で定義されているシグナル名、またはシグナル番号です。
シグナル名は大文字小文字は区別されず、先頭の SIG は省略可能です。
sigspec が EXIT (0) であれば、シェルの終了時にコマンド arg が実行されます。
sigspec が DEBUG であれば、
各々の 単純なコマンド、for コマンド、case コマンド、select コマンド、各々の算術 for コマンドの前、
およびシェル関数の最初のコマンドの実行前 (前述の シェルの文法セクションを参照) に、
コマンド arg が実行されます。
DEBUG のトラップの影響についての詳細は組み込みコマンド shopt の extdebug オプションの説明を
参照してください。
sigspec が RETURN であれば、シェル関数の実行、
または組み込みコマンドの . や source で実行されたスクリプトの実行が終わるたびに
コマンド arg が実行されます。
sigspec が ERR であれば、 単純なコマンドが 0 以外の終了ステータスのときに
コマンド arg が実行されます。
ただし、失敗したコマンドが、 while または until キーワード直後のコマンドリストに含まれる場合、
if 文の条件に含まれる場合、 && や || のリスト中で実行するコマンドに含まれる場合、
および、コマンドの戻り値が ! で反転されている場合には、 ERR のトラップは実行されません。
これらは errexit オプションが従う条件と同じです。
シェルに入る際に無視されるシグナルは、トラップもリセットもできません。
無視されなかったシグナルのトラップは、 サブシェルやサブシェル環境では作られたときに
元の値にリセットされます。
sigspec のいずれかが不正であれば、返却ステータスは偽になります。
それ以外の場合には、 trap は真を返します。
man bash より引用
4.1 ステップ実行
- trapに渡す
sigspec
にDEBUG
を指定することでステップ実行できる
trap 'read -p "$0($LINENO) $BASH_COMMAND"' DEBUG`
#!/bin/bash
: [DEBUG] set param
readonly SCORE_ARRAY=(100 90 80 70)
readonly COUNTS=${#SCORE_ARRAY[@]}
function cal_score_ave() {
local _score_sum=i
: [DEBUG] cal
for _score in ${SCORE_ARRAY[@]}
do
_score_sum=$((_score_sum + _score))
done
score_ave=$((_score_sum / COUNTS))
return 0
}
trap 'read -p "$0($LINENO) $BASH_COMMAND"' DEBUG
: [DEBUG] main
cal_score_ave
echo $score_ave
echo $param
trap – DEBUG
echo "finished"
exit 0
# ./cal_score_ave.sh
./cal_score_ave.sh(5) : [DEBUG] set param
./cal_score_ave.sh(6) readonly SCORE_ARRAY=(100 90 80 70)
./cal_score_ave.sh(7) readonly COUNTS=${#SCORE_ARRAY[@]}
./cal_score_ave.sh(21) : [DEBUG] main
./cal_score_ave.sh(22) cal_score_ave
./cal_score_ave.sh(23) echo $score_ave
85
./cal_score_ave.sh(24) echo $param
./cal_score_ave.sh(25) echo "finished"
finished
./cal_score_ave.sh(27) exit 0
4.2 特定の箇所のみステップ実行する
-
trap - DEBUG
で無効化する
trap 'read -p "$0($LINENO) $BASH_COMMAND"' DEBUG
# ここにステップ実行したい処理
trap - DEBUG
#!/bin/bash
: [DEBUG] set param
readonly SCORE_ARRAY=(100 90 80 70)
readonly COUNTS=${#SCORE_ARRAY[@]}
function cal_score_ave() {
local _score_sum=i
: [DEBUG] cal
for _score in ${SCORE_ARRAY[@]}
do
_score_sum=$((_score_sum + _score))
done
score_ave=$((_score_sum / COUNTS))
return 0
}
trap 'read -p "$0($LINENO) $BASH_COMMAND"' DEBUG
: [DEBUG] main
cal_score_ave
echo $score_ave
echo $param
trap - DEBUG
echo "finished"
exit 0
# ./cal_score_ave.sh
./cal_score_ave.sh(20) : [DEBUG] main
./cal_score_ave.sh(21) cal_score_ave
./cal_score_ave.sh(22) echo $score_ave
85
./cal_score_ave.sh(23) echo $param
./cal_score_ave.sh(24) trap - DEBUG
finished
4.3 エラーのみ捕捉する
- trapに渡す
sigspec
にERR
を渡すことでエラーのみ捕捉することができる
trap 'read -p "$0($LINENO) $BASH_COMMAND":exit 1' ERR`
#!/bin/bash
trap 'read -p "$0($LINENO) $BASH_COMMAND";exit 1' ERR
: [DEBUG] set param
readonly SCORE_ARRAY=(100 90 80 70)
readonly COUNTS=${#SCORE_ARRAY[@]}
function cal_score_ave() {
local _score_sum=i
: [DEBUG] cal
for _score in ${SCORE_ARRAY[@]}
do
_score_sum=$((_score_sum + _score))
done
score_ave=$((_score_sum / COUNTS))
#return 0
return 1
}
: [DEBUG] main
cal_score_ave
echo $score_ave
echo $param
echo "finished"
exit 0
# ./cal_score_ave.sh
./cal_score_ave.sh(19) return 1