LoginSignup
1

More than 3 years have passed since last update.

bashでデバック用に変数表示を簡単に実装する(何もしないコマンド":"を使う)。

Last updated at Posted at 2019-06-16

目的

  • bashで複数のファイルをRなどにパラメータと共に渡すときに、デバックモードになると変数の値を表示させたいなーと常々思っていました。

  • その方法を思いついたので備忘録として残したいと思います。何かのお役に立てれば嬉しいです

方針

  • 方針はシンプルにシンプルに。なのでgetoptsなんかは使わ(え)ないです。
  • bash:は何もしない性質を利用します(今日これを見つけました。先般諸氏ありがとうございます)
  • testコマンド[]の論理連結で[] && []などを多用します。
  • ユーザ関数を定義しておきます(abort())。次のように記述します。
function abort {
   echo "$@" 1>&2
   exit 1
}

これでファイルがないと止められます。

 [ -f $filename ] || abort "$filenameがないので終了します"

メカニズムですが、ファイルがないと[]の中がFALSEと判定されて||で次のコマンドに進み、abort()関数が呼ばれ、メッセージを出して止まります。エラーコードは1です。

引数でデバックモードの切り替え

引数でmodeが設定されれば、表示して何もしないようにするには下記のようにしました。

mode=${1}; # 引数をmodeに設定します。
debug=":"; # これがポイント。$modeが設定されていない場合に用いられます
[ ! -z $mode ] && dryrun="echo dryrun>"

hoge=$(何かの処理); 
$dryrun "hoge=${hoge}"; 

modeが設定されないと:で何もしません。設定されるとecho dryrun>が呼ばれて、後ろの文字列も表示されます。dryrun>は任意でどうぞお使いくだしあ。実際の例を見てみましょう。

実際の例

modedryrundebugの2つの機能を持たせたコードの例です。

tmp.bash
#!/usr/local/bin/bash 

abort(){ echo "$@" 1>&2 ; exit; }

# 引数の解析
inputfile=${1}; 
[ -z ${inputfile} ] && abort "inputfileが設定されていません"
[ -f ${inputfile} ] || abort "${inputfile}がありません"
shift; [ $# -gt 0 ] && mode=${1}

debug=":"
[ ! -z $mode ] && [ $mode = "dryrun" ] && dryrun="echo dryrun>"
[ ! -z $mode ] && [ $mode = "debug" ]  && debug="echo debug>"

_dir=$( dirname ${inputfile} );
$debug "_dir=${_dir}";

backup="${inputfile}.bak"; 
[ ! -f $backup ] && $dryrun cp $inputfile $backup;

ちょっと解説

[ -z ${inputfile} ] &&は変数が設定されていないと次に進みます。
[ -f ${inputfile} ] ||は変数がファイルでないならは次に進みます。
shiftは引数をシフトします。そのため、次の引数呼び出しは必ず$1でOKです。ただし、引数があるかを[ $# -gt 0 ]で調べています。

debug=":"が今回組み合わせを思いついた方法です。通常モードは$debug以降を何もしません。
modeが設定されればdebugechoする機能に切り替わります。

ここで[ ! -z $mode ]ですが$modeが設定されていないと[ = "test" ]と解釈され、すなわち空白と"test"が比較されます。そんなことできない(-bash: [: =: 単項演算子が予期されます)と怒られるので、設定を確認するためのものです。その前の[ $# -gt 0 ]でチェックしているので設定が担保されているのですが、バグが少ないような書き方として載せました。

modeが設定されない通常モードなら、_dirは表示しませんがdebugモードなら表示されます。
注意としてこのスクリプトではdebugモードの時はdryrunになにも設定しないので最終行は実行されてしまいます。つまりバックアップファイルが生成されます。この辺りはご自身の要求で変更してみてください。
modedryrunなら最終行は期待通りコマンド(cp $inputfile $backup)を変数展開し表示するだけで実行はしません。

幾つか実行してみますね。

~$ ll a*
ls: cannot access 'a*': No such file or directory

~$ tmp.bash
inputfileが設定されていません

~$ tmp.bash a
aがありません

~$ touch a
~$ tmp.bash a dryrun
dryrun> cp a a.bak

~$ ll a*
-rw-r--r-- 1 osaka 0  6 16 23:03 a

~$ tmp.bash a debug
debug> _dir=.

~$ ll a*
-rw-r--r-- 1 osaka 0  6 16 23:03 a
-rw-r--r-- 1 osaka 0  6 16 23:03 a.bak

~$ rm a.bak
~$ tmp.bash a
~$ ll a*
-rw-r--r-- 1 osaka 0  6 16 23:03 a
-rw-r--r-- 1 osaka 0  6 16 23:03 a.bak

まあ、動いていそうです。

参考にさせていただきましたいくつかのリンクを貼っておきます。

先輩の方々のお陰で何か成長している気がします。

何かのお役に立てれば嬉しいです。

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
1