web-dev-qa-db-ja.com

X ""で空の文字列をテストします

-zを使用してBashの空の文字列をテストできることはわかっています。

if [[ -z $myvar ]]; then do_stuff; fi

しかし、私は次のように書かれた多くのコードを見ます:

if [[ X"" = X"$myvar" ]]; then do_stuff; fi

その方法はより移植性がありますか? -zの時代以前からの歴史的な問題ですか? POSIXシェル用ですか(bashを対象とするスクリプトで使用されているのを見ていても)。履歴/移植性のレッスンの準備ができました。


サーバーフォールトで同じ質問が bash変数が空かどうかを判断する方法? が尋ねられましたが、whyX""のコードが表示されます。

74
mgalgs

根本的に、これまで長い間、testの動作はより複雑で、異なるシステム間で一律に定義されていなかったためです(したがって、移植性のない構造を避けるため、移植可能なコードを慎重に記述する必要がありました)。

特に、testがShellビルトインになる前は、別個の実行可能ファイルでした(そして、MacOS Xにはまだ/bin/testおよび/bin/[実行可能ファイルとして)。その場合、次のように書きます。

if [ -z $variable ]

いつ $variableが空だった場合、エイリアスを介してテストプログラムを呼び出します[ 3つの引数:

argv[0] = "["
argv[1] = "-z"
argv[2] = "]"

変数が空だったため、展開するものがなかったからです。したがって、コードを記述する安全な方法は次のとおりです。

if [ -z "$variable" ]

これは確実に機能し、test実行可能ファイルに4つの引数を渡します。確かに、テストプログラムは何十年もの間ほとんどのシェルに組み込まれてきましたが、古い機器は死に絶えます。

Xプレフィックスによって解決された他の問題は、変数に先頭のダッシュが含まれている場合、または等号または他のコンパレーターが含まれている場合に発生することでした。考えてみてください(それほど良い例ではありません):

x="-z"
if [ $x -eq 0 ]

それは、浮遊(誤った)引数を使用した空の文字列テストですか、それとも非数値の最初の引数を使用した数値の等価テストですか? 1990年頃、POSIXが動作を標準化する前に、さまざまなシステムがさまざまな回答を提供しました。したがって、これに対処する安全な方法は次のとおりでした。

if [ "X$x" = "X0" ]

または(私の経験ではあまり一般的ではありませんが、完全に同等です):

if [ X"$x" = X"0" ]

このようなすべてのEdgeケースは、テストが個別の実行可能ファイルである可能性と結びついていました。つまり、ポータブルシェルコードは、実際に現代のシェルが必要とするよりも二重引用符を多く使用し、Xプレフィックス表記が使用されたことを意味します物事が誤解されないようにしてください。

116

ああ、これは私の好みの質問と回答の1つです。なぜなら、私はそれについて考えているだけの答えを思いついたからです。 Xは、文字列が-で始まる場合にのみ設定され、テストのフラグとして使用できます。 Xを前に置くと、そのケースが削除され、比較が保持されます。

また、この種のトリックは過去の最も古いコンピューティングの時代からの継承であり、最もポータブルなシェルスクリプト(autoconf、configureなど)を読み取ろうとすると遭遇するため、これも気に入っています。

11
Diego Sevilla