81

これは、autotools(autoconf、automake)を使用するプロジェクトのビルドスクリプトでよく見られます。誰かがシェル変数の値をチェックしたいとき、彼らは頻繁にこのイディオムを使用します:

if test "x$SHELL_VAR" = "xyes"; then
...

単に次のように値をチェックするよりも、これの利点は何ですか。

if test $SHELL_VAR = "yes"; then
...

私はこれを頻繁に見る理由があるに違いないと思いますが、それが何であるかを理解することはできません。

4

7 に答える 7

98

単純な置換を行うシェルを使用していて、SHELL_VAR変数が存在しない(または空白である)場合は、エッジケースに注意する必要があります。次の翻訳が行われます。

if test $SHELL_VAR = yes; then        -->  if test = yes; then
if test x$SHELL_VAR = xyes; then      -->  if test x = xyes; then

これらの最初の引数は、への最初の引数testが欠落しているため、エラーを生成します。2番目はその問題はありません。

あなたのケースは次のように解釈されます:

if test "x$SHELL_VAR" = "xyes"; then  -->  if test "x" = "xyes"; then

x少なくともPOSIX準拠のシェルの場合、引用符は空の引数とスペースを含む引数の両方が単一のオブジェクトとして解釈されるため、実際には冗長です。

于 2008-10-06T13:29:01.000 に答える
24

誰もまだ言及していないもう 1 つの理由は、オプション処理に関連するものです。あなたが書く場合:

if [ "$1" = "abc" ]; then ...

$1 の値が「-n」の場合、テスト コマンドの構文があいまいです。何をテストしていたのかは明確ではありません。先頭の「x」は、先頭のダッシュが問題を引き起こすのを防ぎます。

-ntest コマンドがorをサポートしていないシェルを見つけるには、本当に古いシェルを調べる必要が-zあります。バージョン 7 (1978)testコマンドにはそれらが含まれていました。それは全く無関係というわけではありません - 一部のバージョン 6 UNIX のものは BSD にエスケープされましたが、最近では、現在使用されている古いものを見つけるのは非常に困難です。

他の多くの人が指摘しているように、値を二重引用符で囲まないことは危険です。実際、ファイル名にスペースが含まれる可能性がある場合 (MacOS X と Windows はどちらもある程度それを推奨しており、Unix は常にそれをサポートしていますが、xargs難しくする)、ファイル名を使用するたびに二重引用符で囲む必要があります。値を管理していない限り (たとえば、オプションの処理中に、起動時に変数を「no」に設定し、コマンド ラインにフラグが含まれている場合は「yes」に設定する)、引用符で囲まれていない形式の変数を使用するのは安全ではありません。それらが安全であることを証明するまで、そして多くの目的のために常にそれを行うこともできます. または、ユーザーが名前に空白を含むファイルを処理しようとすると、スクリプトがひどく失敗することを文書化します。(そして、他にも心配すべき文字があります。たとえば、バッククォートもかなり厄介なものになる可能性があります。)

于 2008-10-07T22:00:01.173 に答える
12

この大会で私が知っている理由は2つあります。

http://tldp.org/LDP/abs/html/comparison-ops.html

複合テストでは、文字列変数を引用するだけでは不十分な場合があります。[-n "$ string" -o "$ a" = "$ b"]は、$ stringが空の場合、Bashの一部のバージョンでエラーを引き起こす可能性があります。安全な方法は、空の可能性のある変数に余分な文字を追加することです["x $ string"!= x -o "x $ a" = "x $ b"]( "x"はキャンセルされます)。

次に、Bash以外のシェル、特に古いシェルでは、空の変数をテストするための「-z」のようなテスト条件が存在しなかったため、次のようになります。

if [ -z "$SOME_VAR" ]; then
  echo "this variable is not defined"
fi

BASHで正常に動作します。デフォルトのシェルがBashであり、-zテスト条件をサポートしているかどうかを確認できないさまざまなUNIX環境間での移植性を目指している場合は、フォームを使用する方が安全です。 x $ SOME_VAR "=" x"]これは、常に意図した効果があるためです。基本的に、これは空の変数を見つけるための古いシェルスクリプトのトリックであり、よりクリーンなメソッドが利用可能であるにもかかわらず、下位互換性のために今日でも使用されています。

于 2008-10-06T13:41:06.670 に答える
2

私はそれが原因だと思います

SHELLVAR=$(true)
if test $SHELLVAR  = "yes" ; then echo "yep" ; fi 

# bash: test: =: unary operator expected

と同様

if test $UNDEFINEDED = "yes" ; then echo "yep" ; fi
# bash: test: =: unary operator expected

SHELLVAR=" hello" 
if test $SHELLVAR = "hello" ; then echo "yep" ; fi
# yep 

ただし、これは通常は機能するはずです

SHELLVAR=" hello"
if test "$SHELLVAR" = "hello" ; then echo "yep" ; fi 
#<no output>

しかし、それがどこか別の場所で出力に不平を言っているとき、私が推測することについて不平を言っていることを伝えるのは難しいので、

SHELLVAR=" hello"
if test "x$SHELLVAR" = "xhello" ; then echo "yep" ; fi 

同様に機能しますが、デバッグが簡単になります。

于 2008-10-06T13:00:42.633 に答える
0

SHELL_VARが未定義の場合、DOSでこれを実行していました。

于 2008-10-06T12:51:46.770 に答える
0

「x$SHELL_VAR」を実行しない場合、$ SHELL_VARが未定義の場合、「=」がモナディック演算子などではないというエラーが発生します。

于 2008-10-06T13:01:05.130 に答える