oinume journal

Scratchpad of what I learned

direnvから.envをロードする

.envrcファイルに dotenv と書くだけで、現在いるディレクトリの .env ファイルを読んでくれる素敵な仕様を発見した。これでdirenv使いながら.env形式しか受け付けないアプリケーションにも対応できてめでたしめでたし。

以下は具体的な例。

$ cat .env
PORT=12345
ENV=local

$ cat .envrc
dotenv

$ direnv allow
direnv: loading .envrc
direnv: export +ENV +PORT

$ echo $ENV $PORT
local 12345

Shellでset -uした時の引数の取り扱い

 

#!/bin/sh

 

DIR=$1

 

rm -rf $DIR/

 

なんてやると$1がなかった時に / が消されてしまうので非常に危険。こういう場合は set -u して、未定義の変数があればエラーにすることが推奨される。

 

/Users/kazuhiro/Dropbox/code/sh/set_u.sh: line 3: $1: unbound variable

 

 

ただし、 set -u すると引数の個数を$#を使って、いちいちチェックしないといけない。

 

 

#!/bin/sh

set -u

 

# 引数のサイズをチェック

if [ $# -le 1 ]; then

exit 1

fi

DIR=$1

 

rm -rf $DIR/

 

 

ちょっと面倒だけど set -u している時は $# 使いましょうということで。

Shellでset -e の状態を解除するにはset +e

"set -e": 実行コマンドが0以外の終了コードの場合、シェルスクリプトを終了する - RX-7乗りの適当な日々にある通り、Shellスクリプトで set -e すると実行結果が0以外の場合、勝手にスクリプトが終了する。で、この挙動をスクリプトの途中で元に戻したい(=エラーにしたくない)場合は以下のように set +e すればいい。

 

set -e

echo "in set -e"

...

set +e

hoge

echo "in set +e"

 

これで hoge でコマンドが失敗してもエラーでShell自体は終了しなくなる。

[tmkm-amazon]4797321946[/tmkm-amazon]

Shellでgetoptsを使ってコマンドライン引数の解析

だいぶ前の話、Perlを使わないでShellスクリプトで頑張っていた頃、Shellでコマンドラインオプションの解析をやる時は

 

#!/bin/sh

 

for OPT in $*

do

case $OPT in

'-x' )

FLAG_X="TRUE"

;;

'-y' )

shift

FLAG_Y="TRUE"

VALUE_Y=$1

;;

esac

 

shift

done

 

if [ "$FLAG_X" = "TRUE" ]; then

echo "Option -x specified."

fi

 

if [ "$FLAG_Y" = "TRUE" ]; then

echo "Option -y $VALUE_Y specified."

fi

 

という感じで $* と shift を使ってやっていたのですが、最近 getopts なる素敵なビルトインコマンドを知りました。これを使うと上のスクリプトは下のように書き直すことができます。

 

#!/bin/sh

 

while getopts xy: OPT

do

case $OPT in

"x" )

FLAG_X="TRUE"

;;

"y" )

FLAG_Y="TRUE"

VALUE_Y=$OPTARG

;;

esac

done

 

if [ "$FLAG_X" = "TRUE" ]; then

echo "Option -x specified."

fi

 

if [ "$FLAG_Y" = "TRUE" ]; then

echo "Option -y $VALUE_Y specified."

fi

 

 

スクリプトの行数自体はあんまり変わらないように見えますが、shift 忘れをよくやらかしていたので、それが無くなった分つまらないバグを入れ込まなくなった気がします。

 

getoptsの解説

getopts の引数にオプションの文字を指定しますが、文字のあとに : (コロン)をつけると、引数ありのオプションという扱いになります。さらに

 

$ ./getopts.sh -z

 

のように未定義のオプションを指定すると

 

/home/oinume/tmp/script/getopts.sh: illegal option -- z

 

というように怒られます。このエラーハンドリングを自前でやるには :xy: のように、getopts の引数の文字列の最初を : にすればいいみたい。

 

さらに $OPTIND という変数を下記のように -1 してやることで、オプション以降に与えられた引数を取得することができます。例えば、上のスクリプトに下記を足して

 

shift `expr $OPTIND - 1`

if [ -n "$1" ]; then

echo "Argument $1 specified."

fi

 

 

 

$ ~/tmp/script/getopts.sh -x -y yyy hoge

 

のように実行すると

 

 

Option -x specified.

Option -y yyy specified.

Argument hoge specified.

 

 

となります。getopts を実行すると、$OPTIND にはオプションのインデックス番号が保存されているので、これを -1 して shift してやることで、オプション以降の引数が取得できるようになるという仕組みです。

 

最近はこういうレベルのプログラムだったらPerlで書くことも多かったのですが、Shell でも十分いけそうだと実感しました。

 

[tmkm-amazon]4873112672[/tmkm-amazon]