回答:
短い答え
他の人が言ったように-変な振る舞いを防ぐために常に変数を引用するべきです。したがって、単にecho $ fooの代わりにecho "$ foo"を使用してください。
長い答え
この例では、一見して思われるよりも多くのことが行われているため、さらに説明する必要があると思います。
最初の例を実行した後、おそらくシェルが明らかに実行していると自分で考えたので、混乱がどこにあるのかがわかります。
だからあなたの最初の例から:
me$ FOO="BAR * BAR"
me$ echo $FOO
パラメータ展開後は次と同等です:
me$ echo BAR * BAR
そして、ファイル名の展開後は次と同等です:
me$ echo BAR file1 file2 file3 file4 BAR
そしてecho BAR * BAR
、コマンドラインに入力するだけで、それらは同等であることがわかります。
「*をエスケープした場合、ファイル名の拡張を防ぐことができます」
だからあなたの2番目の例から:
me$ FOO="BAR \* BAR"
me$ echo $FOO
パラメータの展開後は、次のようになります。
me$ echo BAR \* BAR
そして、ファイル名の展開後は次と同等になるはずです:
me$ echo BAR \* BAR
また、コマンドラインに「echo BAR \ * BAR」と直接入力すると、エスケープによってファイル名の拡張が妨げられるため、実際には「BAR * BAR」が出力されます。
では、なぜ$ fooを使用してもうまくいかなかったのでしょうか。
これは、3番目の拡張が行われるためです-引用の削除。bashからの手動引用の削除は次のとおりです。
上記の展開の後、上記の展開のいずれかによって生成されなかった文字「\」、「」、および「」の引用符で囲まれていないすべての出現が削除されます。
したがって、コマンドラインに直接コマンドを入力すると、エスケープ文字は以前の展開の結果ではないため、echoコマンドに送信する前にBASHによって削除されますが、2番目の例では、「\ *」は以前のパラメータ展開の結果、削除されません。その結果、echoは "\ *"を受け取り、それが出力されます。
最初の例との違いに注意してください-「*」は、引用の削除によって削除される文字には含まれていません。
これが理にかなっているといいのですが。最後に同じ結論-引用符を使用してください。パラメータとファイル名の展開のみが機能している場合に論理的に機能するエスケープが機能しない理由を説明しようと思ったところです。
BASH展開の詳細については、以下を参照してください。
http://www.gnu.org/software/bash/manual/bashref.html#Shell-Expansions
この古いスレッドに少し追加します。
通常は使用します
$ echo "$FOO"
ただし、この構文でも問題が発生しました。次のスクリプトを考えてみましょう。
#!/bin/bash
curl_opts="-s --noproxy * -O"
curl $curl_opts "$1"
そのまま*
にに渡す必要がありますcurl
が、同じ問題が発生します。上記の例は機能せず(現在のディレクトリのファイル名に展開されます)、どちらも機能しません\*
。また$curl_opts
、単一の(無効な)オプションとして認識されるため、引用することもできませんcurl
。
curl: option -s --noproxy * -O: is unknown
curl: try 'curl --help' or 'curl --manual' for more information
したがって、グローバルパターンに適用した場合にファイル名が完全に拡張されないようにbash
変数$GLOBIGNORE
を使用するか、set -f
組み込みフラグを使用することをお勧めします。
#!/bin/bash
GLOBIGNORE="*"
curl_opts="-s --noproxy * -O"
curl $curl_opts "$1" ## no filename expansion
元の例に当てはめる:
me$ FOO="BAR * BAR"
me$ echo $FOO
BAR file1 file2 file3 file4 BAR
me$ set -f
me$ echo $FOO
BAR * BAR
me$ set +f
me$ GLOBIGNORE=*
me$ echo $FOO
BAR * BAR
SELECT * FROM etc.
。これが機能する唯一の方法です。
FOO='BAR * BAR'
echo "$FOO"
echo "$FOO"
コマンドラインではprintf
なく、使用する習慣を身につける価値があるかもしれませんecho
。
この例では、あまりメリットはありませんが、より複雑な出力の方が便利です。
FOO="BAR * BAR"
printf %s "$FOO"