シェルのtest コマンド
シェルのtest コマンドの仕様を忘れがちなのでメモしておく。
if 文など条件式を評価する場合には test コマンドを使用する。どのような評価を行うかはオプションにより細かく指定することが可能である。 test コマンドは評価結果に従い、真(0)か偽(1)かの終了ステータスを返すのみで、画面上へのメッセージ出力等は一切行わない条件評価に特化したコマンドである。
数値の比較
test 数値1 -eq 数値2
→ 数値1と数値2が等しいか?(数値1=数値2 ?)
test 数値1 -ne 数値2
→ 数値1と数値2が等しくないか?(数値1≠数値2 ?)
test 数値1 -lt 数値2
→ 数値1は数値2より小さいか?(数値1<数値2 ?)
test 数値1 -gt 数値2
→ 数値1は数値2より大きいか?(数値1>数値2 ?)
test 数値1 -le 数値2
→ 数値1は数値2以下か?(数値1≦数値2 ?)
test 数値1 -ge 数値2
→ 数値1は数値2以上か?(数値1≧数値2 ?)
test コマンドは与えられた2つの数値を比較し、それらの等価・大小を評価することができる。比較条件は実行時に指定されたオプションにより決定される。
使用可能な比較条件を以下の表にまとめる。
testコマンドの数値比較条件一覧表
| オプション | 使用例 | オプションの意味 | ※ 数式で表すと… |
|---|---|---|---|
-eq |
test num1 -eq num2 |
num1 と num2 が等しければ真となる。 | num1=num2 |
-ne |
test num1 -ne num2 |
num1 と num2 が等しくなければ真となる。 | num1≠num2 |
-lt |
test num1 -lt num2 |
num1 が num2 より小ならば真となる。 | num1<num2 |
-le |
test num1 -le num2 |
num1 が num2 以下ならば真となる。 | num1≦num2 |
-gt |
test num1 -gt num2 |
num1 が num2 より大ならば真となる。 | num1>num2 |
-ge |
test num1 -ge num2 |
num1 が num2 以上ならば真となる。 | num1≧num2 |
参考 ~ 数値比較条件に関して
比較条件に使用する -lt や -ge などは、一般的な数学記号の「<」や「≧」などに比べて覚えにくい印象を持つかもしれなが、それぞれが何の略語になっているかを考えると比較的簡単にに覚えられる。
・-eq → equal
・-ne → not equal
・-lt → less than
・-le → less than or equal
・-gt → greater than
・-ge → greater than or equal
文字列の比較
test 文字列1 = 文字列2
→ 文字列1と文字列2は等しいか?
test 文字列1 != 文字列2
→ 文字列1と文字列2は等しくないか?
testコマンドは与えられた2つの文字列を比較し評価することができる。比較条件は「=」と「!=」の2種類があり、「=」を使用した場合は比較する2つの文字列が一致するときに真(終了ステータスが「0」)となる。「!=」を使用した場合は、逆に比較する2つの文字列が一致しないときに真となる。
ファイルの比較
test ファイル1 -nt ファイル2
→ file1 の方が新しいか?
test ファイル1 -ot ファイル2
→ file1 の方が古いか?
test コマンドは2つのファイルのタイムスタンプを比較し評価することができる。比較方法は2種類あり、前者の「-nt」は「ファイル1 is newer than ファイル2」を意味し、後者の「-ot」は「ファイル1 is older than ファイル2」を意味する。それぞれ、成立した場合は終了ステータスが真、成立しなかった場合は偽となる。
その他の評価条件
test オプション 対象
→ test コマンドにオプションを指定することで、さまざまな評価を行うことが可能になる。
test コマンドでは数値や文字列の比較といった評価の他にも、”ファイルが存在するか” などの様々な評価が可能である。
test コマンドの数値・文字列比較以外の評価条件一覧表
| オプション | 使用例 | オプションの意味 |
|---|---|---|
-z |
test -z string |
string の文字列長が 0 ならば真となる。 |
-n |
test -n string |
string の文字列長が 0 より大ならば真となる。 |
-d |
test -d file |
file がディレクトリならば真となる。 |
-f |
test -f file |
file が普通のファイルならば真となる。 |
-s |
test -s file |
file が 0 より大きいサイズならば真となる。 |
-e |
test -e file |
file が存在するならば真となる。 |
-r |
test -r file |
file が読み取り可能ならば真となる。 |
-w |
test -w file |
file が書き込み可能ならば真となる。 |
-x |
test -x file |
file が実行可能ならば真となる。 |
AND 条件と OR 条件
test 条件式1 -a 条件式2
test 条件式1 -o 条件式2
test 条件式1 -a 条件式2 -o 条件式3
→ AND と OR を使用して複数の条件式を指定することができる。
test コマンドは「-a」もしくは「-o」を指定することにより、複数の条件式の終了ステータスから論理演算を行うことができる。つまり「条件式1が成り立ちかつ条件式2が成り立つ場合は真」、「条件式1もしくは条件式2のどちらかが成り立つ場合は真」といったような評価を行うことが可能である。「-a」は「AND(かつ)」を意味し、前後の条件式が両方成り立つ場合のみ「真」となる。「-o」は「OR(または)」を意味し、前後の条件式のどちから一方でも成り立てば「真」となる。 また、「-a」は「-o」よりも評価の優先順位が高いので、両方指定した場合は「-a」の評価が先にに行われる。この優先順位は、後述する「()」によるグルーピングで変更可能である。
$ test 1 = 1 -a 1 -eq 1 ; echo $?
0
$ test 1 = 1 -a 1 -ne 1 ; echo $?
1
※↑AND 条件は両方成り立つ場合のみ「真」となる。
$ test 1 = 1 -o 1 -eq 1 ; echo $?
0 $ test 1 = 1 -o 1 -ne 1 ; echo $?
0
※↑OR 条件だとどちらか一方でも成り立っていれば「真」となる。
$ test 1 != 1 -a 1 -ne 1 ; echo $?
1
$ test 1 != 1 -o 1 -ne 1 ; echo $?
1
※↑両方成り立たない場合は当然「偽」となる。
このように「-a」や「-o」を使用することにより、複雑な条件式を評価することが可能になる。
次は AND 条件と OR 条件の優先順位について見てみる。
$ test 1 = 1 -o 1 -ne 1 -a 2 != 2 ; echo $?
0
上記の test コマンドを分かりやすく書くと次のようになる。
test 真 -o 偽 -a 偽
左から順に見ていくと、「-o」の前後が真と偽なのでここは「真」となる。それにより次の「-a」の前後が真と偽になり結果は「偽」となるはずである。だが、上記の使用例にある通り、結果は「真」となっている。これは「-a」の優先順位が「-o」より高いため、「-a」が先に評価されることによる結果である。つまり先に「-a」の前後が評価され、偽と偽なので結果は「偽」となり、最終的に「test 真 -o 偽」が評価され、結果は「真」となったのである。これで「-a」の方が「-o」よりも評価の優先順位が高いということが分かったが、この優先順位は「()」で囲むことにより変更することが可能となる。
$ test ( 1 = 1 -o 1 -ne 1 ) -a 2 != 2; echo $?
1
先ほどと全く同じ条件式ではあるが、「()」で囲んでいることにより結果が異なっていることが分かるだろう。上記の場合は先に「-o」が評価され、「test 真 -o 偽」で「真」となり、次に「-a」が評価され、「test 真 -a 偽」で最終的に「偽」となったのである。なお、この「()」は上記のように必ずエスケープが必要なので注意すること。
略式 test コマンド
[ 文字列1 = 文字列2 ]
[ 数値1 オプション 数値2 ]
[ オプション 評価対象 ]
→ testコマンドは略式の「[ ]」を使用して記述することができる。
if 文など test コマンドを記述する場合は「[ ]」で代用する場合が多い。記述方法は test コマンドの引数をそのまま「[ ]」の中に記述する形になる。ただし、「 [ 」の直後と「 ] 」の直前には必ず半角スペースが必要となる(無いと正常に動作しない)。
$ ["A" = "A"]
bash: [A: command not found
※↑半角スペースが無いのでエラーとなる。
$ [ "A" = "A" ]; echo $?
0
$ [ 1 -ne 1 ]; echo $?
1
$ [ -f file1 ]; echo $?
0
$ [ -f file1 -a "A" = "A" ]; echo $?
0
「[ ]」を使用した test コマンドがうまく動作しないときは、半角スペースを付け忘れていることが多い。エラーが発生した際のシェルスクリプトのデバッグでは、まず半角スペースの付け忘れを疑ってみるとよい。
if 文の使用例
if 文を使用したシェルスクリプト
実際に if 文を使用してみる。if 文の条件式には略式 test コマンドを使用することが多いが、 if 文は終了ステータスを判定するのみなので、ls 等の一般的なコマンドを指定しても問題はない。
if_test1.sh
#!/bin/bash
if ls file1 file2 >/dev/null 2>&1; then
# 古いほうを削除する
if [ file1 -ot file2 ]; then
echo "remove file1."
rm -f file1
else
echo "remove file2."
rm -f file2
fi
else
echo "file not found..."
exit 1
fi
exit 0
このシェルスクリプト if_test1.sh の実行結果は、以下の通りとなる。
$ ls -l
total 1
-rw-r--r-- 1 SUNONE なし 0 Aug 11 07:05 file1
-rw-r--r-- 1 SUNONE なし 0 Aug 11 07:06 file2
-rwxr-xr-x 1 SUNONE なし 231 Aug 11 07:04 if_test.sh*
$ ./if_test.sh remove file1.
※↑古い方の file1 が削除される。
$ touch file1
$ ./if_test.sh
remove file2.
※↑新しく file1 を作成してから実行すると、
今度は file2 の方が古いので削除される。
$ rm -f file*
$ ls -l
total 1
-rwxr-xr-x 1 SUNONE なし 231 Aug 11 07:04 if_test.sh*
$ ./if_test.sh
file not found...
※↑file1、file2 が無い状態で実行すると12行目の else ルートへ。
次は「elif」を使用した複数分岐の例。
if_test2.sh
#!/bin/bash
echo -n 'Input "a" or "b": '
read KEY
if [ "$KEY" = "" ]; then
echo "何も入力されませんでした。"
elif [ "$KEY" = "a" ]; then
echo '"a"が入力されました。'
elif [ "$KEY" = "b" ]; then
echo '"b"が入力されました。'
else
echo "不正な値: $KEY"
fi
exit 0
このシェルスクリプト if_test2.sh の実行結果は、以下の通りとなる。
$ ./if_test2.sh
Input "a" or "b":
何も入力されませんでした。
※↑何も入力せずにそのまま Enter。
$ ./if_test2.sh
Input "a" or "b": a
"a"が入力されました。
$ ./if_test2.sh
Input "a" or "b": b
"b"が入力されました。
$ ./if_test2.sh
Input "a" or "b": z
不正な値: z
※ 上記内容は、「UNIX & Linux コマンド・シェルスクリプト
リファレンス」よりの抜粋です。