if と test コマンドについて
前提知識
概要
ifは、コマンド実行結果(return code) が 0 かそうでないかだけを見ている- それに倣って各コマンドは慣例的に return code に 正常: 0、異常: 非0 (通常1、区別したい場合は2以降) を返す
[ .. ]も実はただのコマンドで、中に記載した条件が 真なら 0、偽なら 1 を返す- 直前のコマンドの return code を確認したい場合は
$?で確認可能- 例えば デバッグ目的で echo したあとは
$?に入るのは echo の結果(通常0) なので注意
- 例えば デバッグ目的で echo したあとは
!は、結果を反転するコマンド(シェル演算子)
ということから、
ifに渡すもの自体は[ .. ]である必要はなく、コマンド自体の return code を使いたい場合は囲わずに直接書く
例1: return code 確認
bash
ls /no/such/file 2> /dev/null
echo $? # => 1 と出る
echo $? # => 0 と出る (1個前の echo コマンドは成功しているから)
例2. test コマンド if [ .. ] での判定
bash
if [ "$x" = "" ]; then
echo "x is empty"
fi
例3. コマンド実行自体 if <command> での判定
bash
if ! ls /no/such/file 2> /dev/null; then
echo "file not found"
fi
例4. コマンド実行直後、 $? で判定
bash
ls /no/such/file
if [ $? -ne 0 ]; then
echo "file not found"
fi
デバッグ目的で echo するとハマるので注意
bash
ls /no/such/file
echo $? # => 1 と出るが、コマンド結果は 0
if [ $? -ne 0 ]; then
echo "file not found" # 一生通らなくなってしまう
fi
その場合は、面倒でも変数に入れる
bash
ls /no/such/file
r=$?
echo $r # => 1
if [ $r -ne 0 ]; then
echo "file not found"
fi
test コマンドの演算子について
論理演算子系
| 演算子 | 逆向き | 意味 |
|---|---|---|
| = | != | 文字列の 一致/不一致 |
| \> | \< | 文字列の より大/より小 (辞書順) ← 「以上/以下」は存在しない |
| -eq | -ne | 数値の 一致/不一致 |
| -gt | -lt | 数値の より大/より小 |
| -ge | -le | 数値の 以上/以下 |
| -z | -n | カラ文字かどうか (= "" でも同じ) |
| ! | 否定 |
例
if [ "$x" = "abc" ]; then
echo "ok"
fi
ファイル系
| 演算子 | 意味 |
|---|---|
| -f | 通常ファイルかかどうか |
| -d | ディレクトリかどうか |
| -L | シンボリックリンクかどうか |
| -e | ファイル/ディレクトリ 等の区別なく、存在チェック |
| -r | 権限: 読み取り可能 (read) |
| -w | 権限: 書き込み可能 (write) |
| -x | 権限: 実行可能 (execute) |
例
if [ ! -f "a.txt" ]; then
echo "not found"
fi
二重のカッコ [[ .. ]] について
[[ .. ]]は Bash 固有の機能(というより ksh から取り込まれた拡張)で、条件に使える文がちょっと便利になる
| # | やりたいこと | [ .. ] 版 | [[ .. ]] 版 | [[ .. ]] で うれしいこと |
|---|---|---|---|---|
| 1 | 文字列の一致など | [ "$x" = "abc" ] | [[ $x = "abc" ]] | クォートなくても事故りづらい (カラ文字のケースなど) |
| 2 | 正規表現での一致 | [ `echo "$x" | grep -c "^abc"` -gt 0 ] | [[ $x =~ ^abc.* ]] | 構文として存在する |
| 3 | glob での一致 | なし | [[ $x == abc* ]] | 構文として存在する |
| 4 | and | [ .. ] && [ .. ] | [[ .. && .. ]] | どちらでも良いな |
| 5 | or | [ .. ] || [ .. ] | [[ .. || .. ]] | どちらでも良いな |
| 6 | 文字列の大小 | \\>, \\< | >, < | エスケープが不要 |
※ 2 の [ 版の例については、grep -q (結果を return code で判別) とするほうが良いが、[ を使う例として、無理やりこうした
and, or について補足
昔ながらの書き方 (POSIX準拠という)
bash
if [ "$x" -eq 0 ] && [ "$y" -eq 0 ]; then
Bash 前提の書き方でも良いなら
bash
if [[ $x -eq 0 && $y -eq 0 ]]; then
以下広告