42

これらは宣伝どおりに機能します。

grep -ir 'hello world' .
grep -ir hello\ world .

これらはしません:

argumentString1="-ir 'hello world'"
argumentString2="-ir hello\\ world"
grep $argumentString1 .
grep $argumentString2 .

2 番目の例では引用符'hello world'で囲まれていますが、grep は (and ) を 1 つの引数として解釈し'hellohello\( world'and world) を別の引数として解釈します。つまり、この場合、'helloが検索パターンworld'になり、検索パスになります。

繰り返しますが、これは引数がargumentString変数から展開された場合にのみ発生します。最初の例では、 grep は'hello world'(およびhello\ world) を単一の引数として適切に解釈します。

これがなぜなのか説明できる人はいますか?シェルコマンドによって正しく解釈されるように、各文字の構文を保持する文字列変数を展開する適切な方法はありますか?

4

3 に答える 3

45

なぜ

文字列が展開されると、単語に分割されますが、引用符やドル記号などの特殊文字を見つけるために再評価されることはありません...これは、Bourneシェルが戻って以来、シェルが「常に」動作する方法です。 1978年頃。

修理

ではbash、配列を使用して引数を保持します。

argumentArray=(-ir 'hello world')
grep "${argumentArray[@]}" .

または、勇敢/愚か者の場合は、次を使用しますeval

argumentString="-ir 'hello world'"
eval "grep $argumentString ."

一方、多くの場合、裁量は勇気の大部分であり、協力することevalは勇気よりも裁量が優れている場所です。'dである文字列を完全に制御できない場合eval(厳密に検証されていないユーザー入力がコマンド文字列にある場合)、潜在的に深刻な問題が発生する可能性があります。

Bashの拡張のシーケンスは、GNUBashマニュアルのシェル拡張で説明されていることに注意してください。特定のセクション3.5.3シェルパラメータ拡張、3.5.7ワード分割、および3.5.9引用符の削除に注意してください。

于 2012-08-27T06:19:30.657 に答える
6

引用符を変数に入れると、それらは単純なリテラルになります(http://mywiki.wooledge.org/BashFAQ/050を参照してください。このリンクを指摘してくれた@tripleeeに感謝します)

代わりに、配列を使用して引数を渡してみてください。

argumentString=(-ir 'hello world')
grep "${argumentString[@]}" .
于 2012-08-27T06:18:22.773 に答える