二重引用符の中に「!」をエスケープしてください。

二重引用符の中に「!」をエスケープしてください。

bashは手動で二重引用符を入力します(https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html)状態:

有効にすると、「!」が二重引用符内に表示され、バックスラッシュでエスケープされない限り、履歴拡張が実行されます。前の「!」のバックスラッシュは削除されません。

なぜ特別なケースがありますか!?たとえば、aをエスケープすると、$出力にバックスラッシュが表示されません(例:echo "\$"->$echo "\!"->比較\!)。

!二重引用符の中にテキストだけを入れるにはどうすればよいですか?

この問題に対する1つの制限は、bash呼び出し形式を簡単に操作できないことです。私の言葉は、単一の二重引用符文字列を使用してコマンドを実行するのに止まったことです。 my-command "a string I generate in an external program that may contain !"

文字列の生成方法を制御できますが、コマンドラインから分割することはできません(たとえば、このようなものは"part1"\!"part2"私には適していません)。

答え1

!isを使って文字列を印刷するいいえ引用符がない場合、または一重引用符で囲まれている場合は、C文字列またはスクリプト内で問題が発生します。

$ echo hello\!world 'hello!world' $'hello!world'
hello!world hello!world hello!world

$ echo 'echo "hello!world"' >file
$ bash file
hello!world

このスクリプト例は、histexpandがデフォルトで設定されていない特別なケースです。したがって、histexpandを無効にすると(単にorset +o histexpandshopt -ou histexpand同じset +H)、同じ効果を持ち、履歴の拡張を回避できます。

しかし、文字列を複数の部分に分割せずに(デフォルト)対話型シェルで二重引用符で囲まれた文字列を使用するように要求しています。まあ、どうですか?

$ a='!'
$ echo "hello${a}world"
hello!world

歴史についてなぜ?

なぜ特別な場合があるのでしょうか! ?

ほとんどのASCII文字はいいえ特殊(内部"):

$ printf '%s\n' "\a\b\c\d\e\f...\z \!\@\#\%     \$a \`date\` \\"

\a\b\c\d\e\f...\z \!\@\#\%     $a `date` \

関連テキストソースman bash:文字を二重引用符で囲むと、履歴拡張が有効になっている場合は、$、`、\、!を除く引用符内のすべての文字のリテラル値が保持されます。

これは古代のシェルで二重引用符内のバックスラッシュがどのように機能するかです。POSIX仕様反映:

<バックスラッシュ>は、次のいずれかの文字が続く場合に特殊文字として扱われる場合にのみ、エスケープ文字としての特別な意味を維持する必要があります(エスケープ文字(バックスラッシュ)を参照)。

$ `` \ <改行>

答え2

!明らかに、Bashは(過去の拡張を抑制するために)二重引用符の中に現れるエスケープバックスラッシュの使用を削除しません。偽攻撃メーリングリスト。

この行動の歴史的理由は以下で述べられています。すでに持っている答えこれは実際にBashの開発者とメンテナンス者が提供した説明です。バグバッシュ引用チェットレイミに関するニュース:

ちなみに、「!」は一重引用符またはバックスラッシュでのみエスケープできます。 「!」は、POSIX.2の仕様と従来のshアクションによっては、二重引用符内で特に処理される文字の1つではないため、二重引用符は機能しません。

同じソースで!二重引用符を処理する方法について説明します。

「set +o histexpand」を使用して履歴拡張をオフにするか、二重引用符の外にバックスラッシュを使用できます。シェルがインタラクティブでない場合は、通常履歴拡張が有効になっていないため、スクリプトからバックスラッシュを削除することは問題になりません。

(同じステートメントのいくつかのバリエーションがこのメーリングリストにあります。1そして2、Cシェルとの関係も言及されています)。

これらの回避策が利用できない場合:次の質問に対する回答に、さまざまな解決策があります。大きな音を出す方法!たとえば、最初の文字をhistchars使用できない文字に設定したり、同じ変数の3番目の文字を使用して履歴拡張を適用したくないコマンドを起動したりします。

関連情報