bashの判定で-nを使うならダブルクォートする

タイトルがほぼすべてだが、bashの変数判定-nの挙動のメモ

要約

変数の文字列のチェックでは、""で囲ったほうが意図した動作を行いやすい。以下は思いつくまでの経緯。

状況

関数の中で外側で宣言されていた変数を参照しようとすると期待した通りに動かないことがあった。

下の例ではfilepath変数に値がセットされているかどうかで関数の中で分岐を行う場合を考えている。

if文の判定では、[ -n $filepath ]を行い、空でない値がセットされているときに真になるようにした。

filepathは初期状態で空文字""でこのまま関数が実行される場合もあり、そのときは、標準入力を読むようにした。

しかし、初期状態のまま関数を実行したとき、filepathに値がセットされていないにもかかわらず、セットされているかのような振る舞いが行われたので、困惑した。

以下は、そのスクリプト例と対策をしたバージョンと原因を載せておく。

これだと期待通りの動作をしない

まずは期待通りに動かず困惑した例から。

filepathに何かセットすれば普通に判定されるが、そのまま関数を実行するとfilepathに何かセットされているように動く。

# これはおかしい
filepath=""
afunction() {
    echo $filepath
    if [ -n $filepath ]; then
        # filepathが空でもここにくる。
        if [ -f $filepath ]; then
            # ぶっちゃけここまでくる。
            echo "read from $filepath"
        else
            echo "$filepath is not a file"
        fi
    else
        while read line
        do
            echo "read: ${line}"
        done
    fi
}
# そのまま実行
echo "expect to read from stdin"
afunction

妥協策

対策としては単純に-nでなく、-zで文字列の長さが0であることを判定するようにしたらOKだった。

# これはふつうに動く
filepath=""
afunction() {
    echo $filepath
    if [ -z $filepath ]; then
        while read line
        do
            echo "read: ${line}"
        done
    else
        if [ -f $filepath ]; then
            #TODO: read
            echo "read from $filepath"
        else
            echo "$filepath is not a file"
        fi
    fi
}
# そのまま実行
echo "expect to read from stdin"
afunction

原因

単純に-nオペレータによる判定について何か勘違いしているというのが、一番考えられる。

もう少しテストしてみた結果、ダブルクォーテーションで囲っておけば、上の動かない例のものでも問題なく動くことが分かった。

# ncheck.sh
emptyvar=""
avar="hello"

if [ -n $emptyvar ]; then
    echo "pass emptyvar"
fi

if [ -n $avar ]; then
    echo "pass avar"
fi

if [ -n "${emptyvar}" ]; then
    echo "pass emptyvar with double quotes"
fi

if [ -n "${avar}" ]; then
    echo "pass avar with double quotes"
fi

この結果として下の出力が得られる:

$ ./ncheck.sh
pass emptyvar
pass avar
pass avar with double quotes

[ -n "${filpath}" ]が期待通りの動作に必要な記述だったようだ。-n-zも文字列に対する演算子なのでよく考えてみれば当然だった。

文字列変数のチェックならダブルクォートで囲む。

以上です。

タイトルとURLをコピーしました