rcmdnk's blog

20170123_shelllogger_200_200

プログラムを書いている時に出力をDEBUGやERRORと言った レベルに分けておいたりすることがよくあると思いますが、 シェルスクリプトでそんなツールを用意してみました。

ちょっと工夫としては、ファイルへ出力されたりパイプでコマンドに渡す様な時は、 grepとかでやっているように色の装飾などを消す、という作業をしてる点。

Sponsored Links

shell-logger

このレポジトリにあるetc/shell-logger.shsource .../etc/shell-logger.sh等として読み込むと errwarnと言ったメーッセージを表示させるための関数が使える様になり、 それぞれその時刻などとともにフォーマットされてメッセージが出力されます。

インストールは/etc/shell-logger.shを適当なところにおいてそれを読み込んでください。 Mac Homebrewなら

$ brew install rcmdnk/rcmdnkpac/shell-logger

/usr/local/etc/shell-logger.shにインストールされます。

実行してみると

20170123_shelllogger.jpg

こんな感じ。

上の例で最後のnoticeコマンドはパイプで...|catcatにつなげていますが、 catの出力には色がついていません。

コマンドの出力で色を付けるとコマンドラインで見る時には便利ですが、 ファイルに出力するとそのカラーコードに関するエスケープシーケンスが余計について分かりづらくなってしまいます。

grepコマンドなどでは--color=autoというオプションを使うと 出力がコマンドラインなのかファイルなのかなどによってこの色つけを行ったり辞めたりしますが、 これと同じことをしてるわけです。

logger_test.sh
1
2
3
4
5
6
7
8
9
#!/bin/bash

test_command
ret=$?
if [ ret = 0 ];then
  info Command succeeded.
else
  err Command failed!
fi

こんな感じのスクリプトを作れば、test_commandが失敗した時はエラーが出ます。 また、エラー出力は標準エラーに出力されます。

./logger_test.sh > log 2>&1

みたいにすると全てlogに書き出されますが、この際は色の情報はない状態で書き込まれます。

使える関数

出力は以下の5段階あってそれぞれに関数があります。 debug以外にはエイリアスで2つの関数名が充てられています。

LEVEL Functions
DEBUG debug
INFO info, information
NOTICE notice, notification
WARNING warn, warning
ERROR err, error

オプション

Variable Name Description Default
_LOGGER_DATE_FORMAT Output date format. ‘%Y/%m/%d %H:%M:%S’
_LOGGER_LEVEL 0: DEBUG, 1: INFO, 2: NOTICE, 3: WARN, 4: ERROR 1
_LOGGER_STDERR_LEVEL For levels greater than equal this level, outputs will go stderr. 4
_LOGGER_DEBUG_COLOR Color for DEBUG 3 (Italicized. Some terminal shows it as color inversion)
_LOGGER_INFO_COLOR Color for INFO ”” (Use default output color)
_LOGGER_NOTICE_COLOR Color for NOTICE 36 (Front color cyan)
_LOGGER_WARNING_COLOR Color for WARNING 33 (Front color yellow)
_LOGGER_ERROR_COLOR Color for ERROR 31 (Front color red)
_LOGGER_ALWAYS_COLOR Color mode. -1: Always no color. 0: Put color only for terminal output. 1: Always put color. 0
_LOGGER_LEVELS Names printed for each level. Need 5 names. (“DEBUG” “INFO” “NOTICE” “WARNING” “ERROR”)

これらの変数を変更することで表示を変更できます。 変数の設定はshell-logger.shを読み込む前に行っても後に行っても適用されます。

デフォルトでは出力レベルは1(INFO)なのでdebugは出力されません。

また、_LOGGER_STDERR_LEVELが4になっていますが、これによって4以上(ERRORのみ)が 標準エラーに出力されます。

_LOGGER_ALWAYS_COLORを1にするとファイルとかに書き出しても色のコードを残したままに出来ます。

色付けに関しては

_LOGGER_ERROR_COLOR="37;41"

みたいにして複数渡してバックグラウンドと文字色を同時に変える事も可能です。 (色に関しては下記参照。)

shell-logger内で使ってるShell技

出力がファイルなどへの出力かどうか調べる

出力をチェックするには[ -t $n ]というテストコマンドが使えます。 $nは標準出力は1、標準エラーは2でこれらを与えて真ならその出力は ファイルやパイプへの出力ではなくて端末に出している事になります。 なので

1
2
3
4
5
if [ -t 1 ];then
  printf "\e[31mColor!\e[m\n"
else
  printf "Non color\n"
fi

みたいな感じでやってあげるだけ。

ちょっと複雑なケースもしっかりと考慮しない場合もあるみたいですが、 大体の場合はこの程度で十分だと思います。

bash - How to detect if my shell script is running through a pipe? - Stack Overflow

変数が数値であるかどうかチェックする

色々と方法はあると思いますが、exprを使った以下の様なものが 伝統的?な感じです。

1
2
3
4
5
6
7
n="aaa"
expr "$n" + 1 >/dev/null 2>&1
if [ $? -eq 2 ];then
  echo "$n" is not a number.
else
  echo "$n" is number.
fi

exprのマニュアルによると

EXIT STATUS
     The expr utility exits with one of the following values:
     0       the expression is neither an empty string nor 0.
     1       the expression is an empty string or 0.
     2       the expression is invalid.

ということなので、もし$nが数字じゃなくて計算に失敗すると ステータスコードは2になります。

ちょっと面倒なのがたまたま結果が0になってしまうケースは何故かステータスコードが1になるということ。 通常シェルスクリプトだと0以外の終了ステータスはエラー終了なわけですが、 exprでは何故かこの様な形を取っています。

標準エラー出力を直接行うコマンド

同じ関数の中で、受け取ったメッセージを 場合によって標準出力と標準エラー出力を分けたい様な時、 出力部分は同じなので、場合分けして2回書く様なことをしないで 同じ出力なのでまとめて書きたい、と言った場合。

1
2
3
4
5
local _my_printf=printf
if [ "$stderr" ];then
  _my_print=">&2 printf"
fi
eval "$_my_print \"\\e[31mTest output\\e[m\\n\""

こんな感じでコマンドを変数にして、それをevelでやってあげれば まとめて書けます。 >&2の部分だけ最後に足した方が普段使ってる感じにはなりますが コマンドとしてまとめた方がスッキリする感じがするので。

evalに渡すので、後ろの色つけのところとかのエスケープをちょっと気をつけないといけません。 一回余計に\が入ります。

Zshの配列の調整

Bashの配列は0番目から始まりますが、 Zshでは通常1番目から始まります。

これが結構面倒で簡単なシェルスクリプトでも配列があるだけで上手く動かなくなってしまいます。

しかし、Zshではこの辺を調整することが出来て、

1
[ -z "$ZSH_VERSION" ] || emulate -L ksh

すると、kshの動作に近い動きになりますが、この中で配列も0から始まる様になります。 Bashの動作中心で書きたい場合にはこのオプションを付けておけば大分同じ書き方が出来る様になります。

また、この変更は関数内で呼んだ場合はその外へは影響は残らないので 他の部分を特に気にせずに使うことが出来ます。

Z-Shell Frequently-Asked Questions

シェルスクリプトで使う色のチェックなど

前に書いた色のチェックが出来るスクリプト。

この中にあるbin/colcheckで色をチェックできます。また、スクリプトの中に各番号の定義とかも書いてあります。

Sponsored Links
Sponsored Links

« WerckerのタスクをDockerを用いてローカルでテストする Firefoxをリフレッシュした »