シェルスクリプトの場合、文字列の引用符("")は必須ではないため、変数を参照する際の引用符も必須ではありません。
しかし、原則としては付けておく方が安全です。変数を条件式の中で使う場合、引用符がないとエラーになって実行できなくなるケースがあるためです。
次の例を見てみましょう。この「quottest1」スクリプトは、変数TESTSTRに1つ目の引数をセットし、TESTSCRの値がabcだったら「OK」、それ以外の時は「NO」と表示する、という内容です。
#! /bin/bash TESTSTR=$1 if [ $TESTSTR = "abc" ] then echo "OK" else echo "NG" fi
ここでは、“変数TESTSTRの値がabcだったら〜”というつもりで「if [ $TESTSTR = "abc" ]」と書いています。しかし、TESTSTRが定義されていない場合は実行時に「if [ = "abc" ]」となり、文法上の誤りとなり実行できません。
$ chmod +x quottest1 $ ./quottest1 abc OK #← 1つ目の引数がabcなので「OK」と表示された $ ./quottest1 aaa NG #← 1つ目の引数がabcではないので「NG」と表示された $ ./quottest1 ./quottest1: line 3: [: =: unary operator expected NG #↑ 引数がないので変数TESTSTRが定義されておらず、ifの行がエラーになっている
これに対し、「if [ "$TESTSTR" = "abc" ]」としていれば、変数TESTSTRが定義されていない場合は「if [ "" = "abc" ]」となり、文法上の誤りはなくなります。
#! /bin/bash TESTSTR=$1 if [ "$TESTSTR" = "abc" ] then echo "OK" else echo "NG" fi
$ ./quottest1 abc OK #← 1つ目の引数がabcなので「OK」と表示された $ ./quottest1 aaa NG #← 1つ目の引数がabcではないので「NG」と表示された $ ./quottest1 NG #← 引数がない=1つ目の引数がabcではないので「NG」と表示された
ファイル名が入っている想定の変数に、空白入りのファイル名が入っているような場合は、引用符がないとうまく実行できません。
例えば、次の例を見てみましょう。変数FILENAMEにセットされている名前のファイルが存在しているかどうかを調べる、というスクリプトです。
使用イメージとしては、変数FILENAMEにセットするファイル名はキーボードから入力したり、ファイルから入力したりしてチェックするというものですが、ここでは、実験のために変数FILENAMEには直接「01 My Song.mp3」という文字列をセットしています。
そして、$FILENAMEの引用符の有無で実行結果がどのように変わるかを見ています。1つ目のif文は引用符なし、2つ目のif文は引用符ありです。
#! /bin/bash FILENAME="01 My Song.mp3" if [ -f $FILENAME ] #← 1つ目のif文 then echo "$FILENAME is a regular file" else echo "$FILENAME is not a regular file" fi if [ -f "$FILENAME" ] #← 2つ目のif文 then echo "$FILENAME is a regular file" else echo "$FILENAME is not a regular file" fi
1つ目のif文は、実行時は「[ -f $FILENAME ]」が「[ -f 01 My Song.mp3 ]」となります。これは、「[ -f」に対して「01」「My」「Song.mp3」の3つの引数を渡したことになるのでエラーとなります。
これに対し、2つ目のif文は「[ -f "$FILENAME" ]」が「[ -f "01 My Song.mp3" ]」となるので、正しくファイルの存在をテストできます。
実際に実行すると以下のような結果となります。ここでは、動作テスト用に「touch」コマンドであらかじめ「01 My Song.mp3」という名前のファイルを作成しています。
$ touch "01 My Song.mp3" #← 動作テスト用にtouchコマンドでファイルを作成 $ chmod +x quottest2 $ ./quottest2 ./quottest2: line 3: [: too many argument #← 1つ目のif文がエラーになった 01 My Song.mp3 is not a regular file #← エラーのためelse以下が実行されている 01 My Song.mp3 is a regular file #← 2つ目のif文の実行結果
引数なしで実行すると1つ目のif文がエラーになるため、エラーメッセージが表示されています。さらに、ifの判定もFALSEとなっているため、「〜is not a regular file」というメッセージが表示されています。
これに対し2つ目のif文は正しく実行されており、「〜is a regular file」というメッセージが表示されています。
コマンドラインでも事情は同じです。先ほどの例と同じように、環境変数に空白入りのファイル名をセットして、「ls」コマンドの引数として実行してみましょう。
変数FILENAMEに「01 My Song.mp3」をセットし、(1)「ls $FILENAME」のように引用符なしで実行した場合と、(2)「ls "$FILENAME"」と引用符ありで実行した場合を比較しています。
$ FILENAME="01 My Song.mp3" $ ls $FILENAME #← (1)引用符なしで実行 ls: 01: No such file or directory ls: My: No such file or directory ls: Song.mp3: No such file or directory (lsコマンドは「01」と「My」と「Song.mp3」という3つの引数を受け取っている) $ ls "$FILENAME" #← (2)引用符ありで指定 01 My Song.mp3 (lsコマンドは「01 My Song.mp3」を受け取った)
西村 めぐみ(にしむら めぐみ)
PC-9801NからのDOSユーザー。PC-486DX時代にDOS版UNIX-like toolsを経てLinuxへ。1992年より生産管理のパッケージソフトウェアの開発およびサポート業務を担当。著書に『図解でわかるLinux』『らぶらぶLinuxシリーズ』『Accessではじめるデータベース超入門[改訂2版]』『macOSコマンド入門』など。2011年より、地方自治体の在宅就業支援事業にてPC基礎およびMicrosoft Office関連の教材作成およびeラーニング指導を担当。
Copyright © ITmedia, Inc. All Rights Reserved.