154

例えば:

me$ FOO="BAR * BAR"
me$ echo $FOO
BAR file1 file2 file3 file4 BAR

\エスケープ文字を使用して:

me$ FOO="BAR \* BAR"
me$ echo $FOO
BAR \* BAR

明らかにバカなことをしている。

出力を取得するにはどうすればよいBAR * BARですか?

4

7 に答える 7

162

$FOO設定が不十分な場合は引用します。変数参照も引用する必要があります。

me$ FOO="BAR * BAR"
me$ echo "$FOO"
BAR * BAR
于 2008-09-19T14:06:06.723 に答える
114

簡潔な答え

他の人が言ったように、奇妙な動作を防ぐために変数を常に引用する必要があります。したがって、単なるecho $fooの代わりにecho "$foo"を使用してください。

長い答え

この例は、一見したところよりも多くのことが起こっているため、さらに説明する必要があると思います。

最初の例を実行した後、おそらくシェルが明らかにやっていると思ったので、混乱がどこにあるのかがわかります。

  1. パラメータ展開
  2. ファイル名の展開

だからあなたの最初の例から:

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

于 2008-09-19T17:46:31.407 に答える
61

この古いスレッドに少し追加します。

通常、使用する

$ 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
于 2012-11-20T23:43:47.277 に答える
6
FOO='BAR * BAR'
echo "$FOO"
于 2008-09-19T14:05:55.943 に答える
3
echo "$FOO"
于 2008-09-19T14:05:56.083 に答える
3

コマンドラインでprintfはなく、使用する習慣を身につける価値があるかもしれません。echo

この例ではあまりメリットがありませんが、より複雑な出力ではより便利になります。

FOO="BAR * BAR"
printf %s "$FOO"
于 2008-09-19T14:25:56.443 に答える