例えば:
me$ FOO="BAR * BAR"
me$ echo $FOO
BAR file1 file2 file3 file4 BAR
\
エスケープ文字を使用して:
me$ FOO="BAR \* BAR"
me$ echo $FOO
BAR \* BAR
明らかにバカなことをしている。
出力を取得するにはどうすればよいBAR * BAR
ですか?
$FOO
設定が不十分な場合は引用します。変数参照も引用する必要があります。
me$ FOO="BAR * BAR"
me$ echo "$FOO"
BAR * BAR
簡潔な答え
他の人が言ったように、奇妙な動作を防ぐために変数を常に引用する必要があります。したがって、単なる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マニュアルの引用符の削除から:
前述の展開の後、引用符で囲まれていない、上記の展開の結果ではない文字「\」、「」、および「"」はすべて削除されます。
したがって、コマンドをコマンドラインに直接入力すると、エスケープ文字は以前の展開の結果ではないため、BASH は echo コマンドに送信する前にそれを削除しますが、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
FOO='BAR * BAR'
echo "$FOO"
echo "$FOO"
コマンドラインでprintf
はなく、使用する習慣を身につける価値があるかもしれません。echo
この例ではあまりメリットがありませんが、より複雑な出力ではより便利になります。
FOO="BAR * BAR"
printf %s "$FOO"