理系学生日記

おまえはいつまで学生気分なのか

忍者TOOLS

シェルスクリプトにおける [ と [[

シェルスクリプトで条件分岐を書くとき、[ を使ったり [[ を使ったりすることになると思います。

POSIX の test にも記載がありあすが、[test と同じ機能を持つことになっており、同じ実装であることも多いです (ただし、[ として実行されるか、test として実行されるかに依って挙動が変わり得る)。

一方で、[[ は POSIX で定義はされていない、Bash 等の高機能シェルでの拡張になります。

[[[ は、当然ながら同じような機能を持っています。そりゃ、後者は前者の拡張ですからね。一方で、「拡張」であるが故に、[[[ で異なる挙動も存在します。

演算子

たとえば比較の演算としては以下のような挙動のちがいがあったりします。なお、[ への有無については、POSIX 定義という観点であって、シェル実装によっては普通に使えるものもあります。

機能 [ [[ 備考
文字列の大小比較 a \> b a > b [ の場合、リダイレクトと誤解されないようにエスケープが必要です
AND 条件 s1 -a s2 s1 && s2 実際のところ、-a は POSIX で 時代遅れであり、POSIX 標準に準拠する場合は使わないようが良いよ とされてます
OR 条件 s1 -o s2 s1 || s2 同上
パターンマッチ なし $a = a*
正規表現マッチ なし $a =~ ^hoge
ファイルの新旧チェック なし $file1 -nt $file2

このあたりの差異の背景には、POSIX にも記載があります。

Some additional primaries newly invented or from the KornShell appeared in an early proposal as part of the conditional command ([[]]): s1 > s2, s1 < s2, str = pattern, str != pattern, f1 -nt f2, f1 -ot f2, and f1 -ef f2. They were not carried forward into the test utility when the conditional command was removed from the shell because they have not been included in the test utility built into historical implementations of the sh utility.

test

その他の挙動

  • [[ では変数をクオテーションで囲まなくて良い
$ var=''
$ [ $var = '' ] # [ = '' ] と展開されてしまうので NG。クオテーションが必要。
sh: [: =: unary operator expected
$ [[ $var = '' ]
$ file="file name"
$ [ -f $file ]    # スペースを含んでいるので、クオテーションで囲まないと失敗する
sh: [: file: binary operator expected
$ [[ -f $file ]]  # 成功する
  • [[ の場合、( 等をエスケープする必要がありません。
$ [ -f "$file1" -a \( -d "$dir1" -o -d "$dir2" \) ] # グルーピング用の括弧もエスケープの必要有
$ [[ -f $file1 && ( -d $dir1 || -d $dir2 ) ]]

※先述の通り、-a-o は POSIX としては、obsolete とされています。

  • [[ の場合、文字列の大小比較でエスケープする必要がない
$ [ a < b ] # シェルにリダイレクトと解釈される
sh: b: No such file or directory
$ [[ a < b ]]


$ [ a > b ] # こちらはエラーすら出ないで、「正常に」ファイルが作成されてしまう。
$ ls b
b

ポータビリティ

状況にも依りますが、ぼく自身はそこまでポータビリティを重視してシェルスクリプトを書かないといけないとは思っていません。 環境がかわったら、シェルスクリプトから呼びだされるコマンドの挙動もちがうでしょうし、そのまま別環境へ移植というのはまぁ無いだろうと思っています。 それに、ポータビリティを重視するにしても、シェルの個別拡張を使用せずに POSIX だけで書こうというのはすごく難しいですし。。。

そういう考え方なので、[[ の方を使うかな。

参考文献