4種類もある。
成果物
記法一覧
方法 | コード例 | メリット | デメリット |
---|---|---|---|
[[]] |
[[ 0 -eq 0 ]] |
1. 正規表現が使える([[ "text" =~ ^.*$ ]] )2. スペースを含む変数値でもダブルクォート不要( var='a b'; [[ $var = 'a b' ]] )3. 最も可読性がマシ( [[ 0 -eq 0 && 1 -eq 1 ]] ) |
POSIX非互換 |
[] |
[ 0 -eq 0 ] && echo "TRUE" |
短く書ける | 左辺と右辺はスペースを含む場合ダブルクォートする必要あり |
if |
if [ 0 -eq 0 ]; then echo "TRUE"; fi; |
1. プログラミングっぽい 2. ググラビリティある |
1. 冗長かつ可読性低 2. 条件式を変数にできない |
test |
test 0 -eq 0; echo $? |
1. 結果は$? で取得する必要あり面倒(すぐ取得せねば別コマンドの結果で上書きされてしまう)2. 真: 0 , 偽: 1 とふつうと逆でわかりにくい |
上から順に推奨。[[]]
が最も良さそう。
test
を使う意義がわからない。test
は[]
とほぼ同じ。どちらもコマンドである。[]
は最後の引数が]
であることを強いられる点以外すべて同じ。
条件式を可変にする(eval
)
cond="0 -eq 0" match=$(eval [[ "$cond" ]]; echo $?;) echo $match
cond="0 -eq 0" match=$(eval [ "$cond" ]; echo $?;) echo $match
cond="0 -eq 0" match=$(eval test "$cond"; echo $?;) echo $match
真なら0
, 偽なら1
。C言語だと逆なのでわかりにくい。
コード例
#!/bin/bash #set -Ceu echo "----- [[ ]] -----" [[ 0 -eq 0 ]]; echo $? [[ 0 -eq 1 ]]; echo $? [[ 0 -eq 0 ]] && echo "TRUE" [[ 0 -eq 0 ]] && echo "TRUE1"; echo "TRUE2" [[ 0 -eq 1 ]] && echo "TRUE" || echo "FALSE" # 論理演算 [[ 0 -eq 0 && 1 -eq 1 ]] && echo "TRUE" || echo "FALSE" [[ 0 -eq 0 || 1 -eq 2 ]] && echo "TRUE" || echo "FALSE" # 計算 [[ 2**10 -eq 512+512 ]] && echo "Equal" || echo "Not equal" [[ '2 ** 10' -eq '512 + 512' ]] && echo "Equal" || echo "Not equal" # 文字列比較 [[ "a" = "a" ]] && echo "TRUE" || echo "FALSE" [[ "a" = "b" ]] && echo "TRUE" || echo "FALSE" [[ -z "" ]] && echo "TRUE" || echo "FALSE" # ダブルクォート不要 var="a b" [[ $var = "a b" ]] && echo "TRUE" || echo "FALSE" # ワイルドカード [[ '2000-01-01' = *-*-* ]] && echo "Match!!" || echo "Not match..." [[ '2000-01-01' == *-*-* ]] && echo "Match!!" || echo "Not match..." # 正規表現 [[ '2000-01-01' =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]] && echo "Match!!" || echo "Not match..." # なぜかマッチしない \dのメタ文字がない? https://ja.wikipedia.org/wiki/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE [[ '2000-01-01' =~ ^\d{4}-\d{2}-\d{2}$ ]] && echo "Match!!" || echo "Not match..." [[ '2000-01-01' =~ ^[\d]{4}-[\d]{2}-[\d]{2}$ ]] && echo "Match!!" || echo "Not match..." [[ '2000-01-01' =~ ^(\d){4}-(\d){2}-(\d){2}$ ]] && echo "Match!!" || echo "Not match..." echo "----- [ ] -----" [ 0 -eq 0 ]; echo $? [ 0 -eq 1 ]; echo $? [ 0 -eq 0 ] && echo "TRUE" [ 0 -eq 0 ] && echo "TRUE1"; echo "TRUE2" [ 0 -eq 1 ] && echo "TRUE" || echo "FALSE" [ 0 -eq 0 -a 1 -eq 1 ] && echo "TRUE" || echo "FALSE" [ 0 -eq 0 -o 1 -eq 2 ] && echo "TRUE" || echo "FALSE" [ 0 -eq 0 ] && [ 1 -eq 1 ] && echo "TRUE" || echo "FALSE" [ 0 -eq 0 ] || [ 1 -eq 2 ] && echo "TRUE" || echo "FALSE" [ "a" = "a" ] && echo "TRUE" || echo "FALSE" [ "a" = "b" ] && echo "TRUE" || echo "FALSE" [ -z "" ] && echo "TRUE" || echo "FALSE" var="a b" [ "$var" = "a b" ] && echo "TRUE" || echo "FALSE" echo "----- test -----" test 0 -eq 0; echo $? test 0 -eq 1; echo $? echo "----- if -----" if [ 0 -eq 0 ]; then echo "TRUE"; fi; if [ 0 -eq 1 ]; then echo "TRUE"; else echo "FALSE"; fi; if [ 0 -eq 1 ]; then echo "TRUE"; elif [ 0 -eq 0 ]; then echo "ELSE_IF"; else echo "FALSE"; fi; # 複数行 if [ 0 -eq 0 ]; then echo "TRUE" fi if [ 0 -eq 1 ]; then echo "TRUE" else echo "FALSE" fi if [ 0 -eq 1 ]; then echo "TRUE" elif [ 0 -eq 0 ]; then echo "ELSE_IF" else echo "FALSE" fi # 複数行(;なし) if [ 0 -eq 0 ] then echo "TRUE" fi if [ 0 -eq 1 ] then echo "TRUE" else echo "FALSE" fi if [ 0 -eq 1 ] then echo "TRUE" elif [ 0 -eq 0 ] then echo "ELSE_IF" else echo "FALSE" fi
できるだけ短く書きたい。するとif
は書かなくなる。以下のような問題があるから。
- 読みづらい&冗長&覚えづらい
then
,fi
,elif
- 改行多すぎ
- どこに
;
付与すればいいかわかりづらい
どう考えても[[]]
が最善。
条件式
条件式 | 説明 |
---|---|
-a file |
file が存在すれば真。 |
-b file |
file が存在し、かつブロック特殊ファイルならば真。 |
-c file |
file が存在し、かつキャラクター特殊ファイルならば真。 |
-d file |
file が存在し、かつディレクトリならば真。 |
-e file |
file が存在すれば真。 |
-f file |
file が存在し、かつ通常ファイルならば真。 |
-g file |
file が存在し、かつ set-group-id されていれば真。 |
-h file |
file が存在し、かつシンボリックリンクならば真。 |
-k file |
file が存在し、かつ “sticky” ビットが設定されていれば真。 |
-p file |
file が存在し、かつ名前付きパイプ (FIFO) ならば真。 |
-r file |
file が存在し、かつ読み込み可能ならば真。 |
-s file |
file が存在し、かつそのサイズが 0 より大きければ真。 |
-t fd |
ファイル・ディスクリプター fd がオープンされており、かつ端末を参照していれば真。 |
-u file |
file が存在し、 かつ set-user-id ビットが設定されていれば真。 |
-w file |
file が存在し、かつ書き込み可能ならば真。 |
-x file |
file が存在し、かつ実行可能ならば真。 |
-G file |
file が存在し、かつ (実行中のシェルの) 実効グループ ID に所有されていれば真。 |
-L file |
file が存在し、かつシンボリックリンクならば真。 |
-N file |
file が存在し、 かつ前回読み込まれた以降に修正されていれば真。 |
-O file |
file が存在し、かつ (実行中のシェルの) 実効ユーザ ID に所有されていれば真。 |
-S file |
file が存在し、かつソケットならば真。 |
file1 -ef file2 |
file1 と file2 とで デバイス番号と i-ノード番号が同じならば真。 |
file1 -nt file2 |
file1 が (変更日時に関して) file2 より新しいか、 file1 が存在するが file2 が存在しなければ、真。 |
file1 -ot file2 |
file1 が file2 より古いか、 file2 が存在するのに file1 が存在しなければ、真。 |
-o optname |
シェルオプション optname が有効ならば真。後述する組み込みコマンド set に対するオプションの説明中にある -o オプションを参照してください。 |
-v varname |
シェル変数 varname がセットされている (値が代入されている) ならば真。 |
-z string |
string の長さが 0 ならば真。 |
-n string |
string の長さが 0 でなければ真。 |
string1 == string2 string1 = string2 |
文字列が同じならば真。( POSIX に準拠する形で test コマンドを使う場合には = を使う必要がある) |
string1 != string2 |
2 つの文字列が異なれば真。 |
string1 < string2 |
現在のロケールにおいて、string1 が string2 よりも 辞書順で前にある場合に真。 |
string1 > string2 |
現在のロケールにおいて、string1 が string2 よりも 辞書順で後にある場合に真。 |
arg1 OP arg2 |
OP は -eq, -ne, -lt, -le, -gt, -ge. のいずれか。 |
よく使うやつだけ。
FILE=a.txt rm -Rf $FILE [ -f $FILE ] && echo 'ファイルは存在する' || echo 'ファイルは存在しない' touch $FILE [ -f $FILE ] && echo 'ファイルは存在する' || echo 'ファイルは存在しない' rm -Rf $FILE DIR=dir rm -Rf $DIR [ -d $DIR ] && echo 'ディレクトリは存在する' || echo 'ディレクトリは存在しない' mkdir $DIR [ -d $DIR ] && echo 'ディレクトリは存在する' || echo 'ディレクトリは存在しない' rm -Rf $DIR [ -v FILE ] && echo '変数名は存在する' || echo '変数名は存在しない' [ -v FFFF ] && echo '変数名は存在する' || echo '変数名は存在しない' [ -z $FILE ] && echo '変数名は長さゼロ-z' || echo '変数名は長さゼロでない-z' ZERO= [ -z $ZERO ] && echo '変数名は長さゼロ-z' || echo '変数名は長さゼロでない-z' [ -n $FILE ] && echo '変数名は長さゼロでない-n' || echo '変数名は長さゼロ-n' [ -n $ZERO ] && echo '変数名は長さゼロでない-n' || echo '変数名は長さゼロ-n' [ "$FILE" = 'a.txt' ] && echo '文字列は等しい' || echo '文字列は等しくない' [ "$FILE" = 'b.txt' ] && echo '文字列は等しい' || echo '文字列は等しくない' [ "$FILE" != 'a.txt' ] && echo '文字列は等しい' || echo '文字列は等しくない' [ "$FILE" != 'b.txt' ] && echo '文字列は等しい' || echo '文字列は等しくない' [ 1 -eq 1 ] && echo '-eq' [ 1 -ne 2 ] && echo '-ne ' [ 1 -lt 2 ] && echo '-lt' [ 1 -le 1 ] && echo '-le' [ 2 -gt 1 ] && echo '-gt' [ 1 -ge 1 ] && echo '-ge'
参考
- https://fumiyas.github.io/2013/12/15/test.sh-advent-calendar.html
- https://shellscript.sunone.me/if_and_test.html
対象環境
- Raspbierry pi 3 Model B+
- Raspbian stretch 9.0 2018-11-13
- bash 4.4.12
- zenity 3.28.1
- xsel 1.2.0
- xdotool 3.20160805.1
$ uname -a Linux raspberrypi 4.14.98-v7+ #1200 SMP Tue Feb 12 20:27:48 GMT 2019 armv7l GNU/Linux