`[` コマンドを知る

こんにちは、masm11 です。

みなさんは、シェルスクリプトを書きますか? 私はよく書きます。 シェルスクリプトを書いてるとよく出てくる文法が、

if [ "$foo" = "bar" ]; then

です。[] です。今回はこれについて取り上げます。

なお、= とか -ne とか -f とか -x とか、いろいろな機能がありますが、 今回はそういう一般的な使い方の話をするつもりはありません。

[ はコマンド

if の文法は、

if コマンド; then

です。コマンドを実行し、成功 (exit status が 0) の場合は then 以降が実行されます。

なので、[ はコマンドとして実装されています。

最初に例として挙げた

if [ "$foo" = "bar" ]; then

は、[ コマンドに

  • $foo のシェル変数を展開したもの
  • =
  • bar
  • ]

が渡されています。

test コマンドとは

一方で、test というコマンドもあります。

使い方は以下のようになります。

if test "$foo" = "bar"; then

つまり、[test に置き換え、] を省きます。 それだけです。

[test の違い

では、[test の違いは何でしょうか?

違いはほとんどありません。これは、昔の UNIX OS では [test へのシンボリックリンクになっていたことからも 判るとおりです (最近の OS ではシェルの built-in なことも多いです)。

UNIX では、自分がどんな名前で実行されたかを各コマンドが知ることができます。 C では main 関数を以下のように書きます。

int main(int argc, char **argv)

argv[0] を見ればどんなコマンド名で実行されたかが判ります。

また、Ruby では $0 に入っていますし、 Python では sys.argv[0] に入っています。

そして、いくつかのコマンドはコマンド名によって動作を変えます。 test コマンドもその一つで、

  • [ として実行された場合には、最後の引数が ] でなければエラーとする

という仕様です。エラーメッセージは以下のとおりです。

[: missing ']'

test[ の違いはそれだけです。

もし、手元で試して、エラーメッセージが

[: ']' expected

だった場合、それは bash の built-in です。bash で外部コマンドの [ を 実行するには、以下のようにします。

LANG=C command [ 

[ を使う際の注意

[ を使う場合には、一つ注意があります。先ほど以下のように書きました。

  • [ として実行された時には、最後の引数が ] でなければエラーとする

「最後の引数が」です。つまり、

if [ "$foo" = "bar"]; then

だと動かないんですね。この場合、[ コマンドに渡されるのは、

  • $foo のシェル変数を展開したもの
  • =
  • bar]

なので、最後の引数が bar] であって ] ではないからです。

まとめ

…知ってましたよ? ただちょっとミスって本番での最終テストで期待通りの 結果にならなかっただけです (泣)