bashでワイルドカード/アスタリスク文字をエスケープするにはどうすればよいですか?
例えば。
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番目の拡張であるQuote Removalがあるためです。 bashからの手動引用の削除は次のとおりです。
上記の展開の後、上記の展開のいずれにも起因しない文字「\」、「 '」、および「 "」の引用符で囲まれていない出現はすべて削除されます。
したがって、コマンドラインにコマンドを直接入力すると、エスケープ文字は以前の展開の結果ではないため、BASHはechoコマンドに送信する前にそれを削除しますが、2番目の例では、「\ *」は前回のパラメーター展開の結果であるため、削除されません。その結果、エコーは「\ *」を受信し、それが出力されます。
最初の例との違いに注意してください-「*」は、引用の削除によって削除される文字には含まれません。
これが理にかなっていることを願っています。最後に同じで結論-引用符を使用してください。パラメータとファイル名の展開のみが機能している場合に論理的に機能するエスケープが機能しなかった理由を説明したいと思いました。
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
に対する単一の(無効な)オプションとして認識されるため、$curl_opts
も引用できません。
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"
コマンドラインでprintf
ではなくecho
を使用する習慣を身に付ける価値があるかもしれません。
この例では、あまり利点はありませんが、より複雑な出力でより有用になる可能性があります。
FOO="BAR * BAR"
printf %s "$FOO"
echo "$FOO"