214
217

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

bashデバッグTips

Last updated at Posted at 2014-08-15

bashデバッグTips

モチベーション

  • デバッグしやすくしたい

1. Bashオプション(bash -uvx

  • 動作確認用スクリプト
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
echo $param
echo "finished"

exit 0
-uvx
# 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

-u
# bash -u cal_score_ave.sh
cal_score_ave.sh: line 12: i: 展開されていない変数

1.2 bash -v

-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

-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行追加
~/.bashrc
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に渡すsigspecDEBUGを指定することでステップ実行できる
trap 'read -p "$0($LINENO) $BASH_COMMAND"' DEBUG`
trap動作確認コード
#!/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
trap動作確認コード
#!/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に渡すsigspecERRを渡すことでエラーのみ捕捉することができる
trap 'read -p "$0($LINENO) $BASH_COMMAND":exit 1' ERR`
trap動作確認コード
#!/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

214
217
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
214
217

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?