たぶん使わないであろうBashのデバッグ方法
http://d.hatena.ne.jp/dharry/20101121/1290273723
とりあえずBash好きなので、前に覚えたことの復習も兼ねてもう一回書いておきます。
setでデバッグ
’-x’, ’-v’ デバッグは基本ですよね。オプションつけて実行するとスクリプトがストリーキングになります。
$ cat foo.sh for x in `seq 2`; do echo $x done $ bash -x foo.sh ++ seq 2 + echo 1 1 + echo 2 2
でもストリーキング愛好家の中には一部だけ露出したいという人もいます。そんなフェティシズムをお持ちでしたら内部で set をすれば OK です。
$ cat foo.sh [ ${1}x = "-dx" ] && \ set -x for x in `seq 2`; do echo $x done set +x $ ./foo.sh 1 2 $ ./foo -d ++ seq 2 + for x in '`seq 2`' + echo 1 1 + for x in '`seq 2`' + echo 2 2 + set +x
BASH_COMMANDをtrap
Bashには色々な疑似シグナルがあります。
疑似シグナル | タイミング |
---|---|
EXIT | シェルがスクリプトを終了した |
ERR | コマンド、シェル関数から0ではない終了ステータスが返された |
DEBUG | シェルが文を実行した |
RETURN | source または . で実行されたシェル関数/スクリプトが終了した |
またBashには予約されたシェル変数があります。そのひとつが "BASH_COMMAND"です。 *1 BASH_COMMANDは実行しようとしているコマンドが変数に入っています。
BASH_COMMAND
http://linux.die.net/man/1/bash
The command currently being executed or about to be executed, unless the shell is executing a command as the result of a trap, in which case it is the command executing at the time of the trap.
DEBUGシグナルを使うとシェルが文を実行するたびにtrapできるので、スクリプトはヌーディストのようになります。
以下コードはスクリプトの特定の箇所をステップ実行します。trap - DEBUG とすればステップ実行の設定は解除されます。
$ cat foo.sh if [ ${1}x = "-dx" ]; then set -x trap 'read -p "$0($LINENO) $BASH_COMMAND"' DEBUG fi while : do dice=$((${RANDOM}%6+1)) case $dice in 1) echo one;; 2) echo two;; 3) echo three;; 4) echo four;; 5) echo five;; 6) echo six; break;; esac done trap - DEBUG echo ok $ ./foo.sh -d ++ trap 'read -p "$0($LINENO) $BASH_COMMAND"' DEBUG +++ read -p './foo.sh(6) :' ./foo.sh(6) : ++ : +++ read -p './foo.sh(8) dice=$((${RANDOM}%6+1))' ./foo.sh(8) dice=$((${RANDOM}%6+1)) ++ dice=6 ++ case $dice in +++ read -p './foo.sh(9) case $dice in ' ./foo.sh(9) case $dice in +++ read -p './foo.sh(15) echo six' ./foo.sh(15) echo six ++ echo six six +++ read -p './foo.sh(15) break' ./foo.sh(15) break ++ break +++ read -p './foo.sh(18) trap '\'''\'' DEBUG' ./foo.sh(18) trap '' DEBUG ++ trap '' DEBUG ++ echo ok ok
bashdb
ステップ実行ができるのなら gdb ぽく解剖もできるんじゃね?と。案の定 bashdb というgdb風のデバッガがあったりします。
まずはインストール。パッケージがあればパッケージマネージャでインストール。
$ sudo apt-get install bashdb
なければソースからビルドします。 ここからダウンロード (http://sourceforge.net/projects/bashdb/files/)
$ tar xvzf bashdb-3.1-0.09.tar.gz $ cd bashdb-3.1-0.09 $ ./configure $ make $ make install
見事にステップ実行できます。マジに素晴らしいです。
$ bashdb foo.sh Bourne-Again Shell Debugger, release bash-3.1-0.09 Copyright 2002, 2003, 2004, 2006, 2007 Rocky Bernstein This is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. (/root/foo.sh:1): 1: if [ ${1}x = "-dx" ]; then bashdb<0> s (/root/foo.sh:6): 6: while : bashdb<1> s (/root/foo.sh:8): 8: dice=$((${RANDOM}%6+1))
bashdb は bash で書かれています。
$ file /usr/local/bin/bashdb /usr/local/bin/bashdb: Bourne-Again shell script text executable
もちろん BASH_COMMAND を trap しています。
$ grep BASH_COMMAND /usr/local/share/bashdb/* /usr/local/share/bashdb/bashdb-main.inc:trap '_Dbg_debug_trap_handler 0 "$BASH_COMMAND" "$@"' DEBUG /usr/local/share/bashdb/bashdb-trace: trap '_Dbg_debug_trap_handler 0 "$BASH_COMMAND" "$@"' DEBUG /usr/local/share/bashdb/bashdb-trace: trap '_Dbg_debug_trap_handler 0 "$BASH_COMMAND" "$@"' DEBUG /usr/local/share/bashdb/bashdb-trace: trap '_Dbg_debug_trap_handler 0 "$BASH_COMMAND" "$@"' DEBUG /usr/local/share/bashdb/dbg-fns.inc: trap '_Dbg_debug_trap_handler 0 "$BASH_COMMAND" "$@"' DEBUG /usr/local/share/bashdb/dbg-main.inc:trap '_Dbg_debug_trap_handler 0 "$BASH_COMMAND" "$@"' DEBUG /usr/local/share/bashdb/dbg-sig.inc: trap '_Dbg_exit_handler "$BASH_COMMAND"' EXIT /usr/local/share/bashdb/dbg-sig.inc: local trap_cmd="trap '_Dbg_sig_handler $signum \"\$BASH_COMMAND\" \"\$@\"' $name"
その他に、プロンプトを書き換えたり、functraceを設定したり、とても普通のbashでは使うことがないことが盛り沢山です。
$ grep PS4 /usr/local/share/bashdb/* /usr/local/share/bashdb/dbg-cmds.inc: # We've reset some variables like IFS and PS4 to make eval look /usr/local/share/bashdb/dbg-fns.inc: PS4='+ dbg (${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]}\n' $ grep functrace /usr/local/share/bashdb/* /usr/local/share/bashdb/bashdb-trace: set -o functrace