二重引用符内の感嘆符がBashエラーを引き起こすのはなぜですか?


25

これらのコマンドを見てください:

$ notify-send SYNC TIME!
$ notify-send 'SYNC TIME!'
$ notify-send "SYNC TIME!"
bash: !": event not found
$

最初の2つのコマンドは、予想どおり通知バブルを生成します。3番目は、表示されたエラーを示します。

そして

$ echo SYNC TIME!
SYNC TIME!
$ echo 'SYNC TIME!'
SYNC TIME!
$ echo "SYNC TIME!"
bash: !": event not found
$

ここでも、echo最初の2つのコマンドで機能しますが、3番目のコマンドでは機能しません。

ここでは多くの問題(私はこれを使用して計画されていませんが):両方notify-send "SYNC!TIME"echo "SYNC!TIME"ギブbash: !TIME": event not found

しかし、両方notify-sendecho動作します"SYNC! TIME"

誰かがbash: !": event not foundエラーが表示される理由を説明できますか?

回答:


31

!Bashのデフォルトの履歴展開文字です。Bashのマンページの「履歴の展開」セクションを参照してください

  • がのように!一重引用符で囲まれている場合、履歴の展開は行われません。

    notify-send 'SYNC TIME!'
  • 場合は履歴展開は行われません!スペース、タブ、改行、キャリッジリターン、または続いて=のように、

    notify-send SYNC TIME!
  • 履歴展開はないで場所を取ります

    echo "SYNC TIME!"

    したがって"、履歴で始まるコマンドがない場合はエラーが発生します


4
この誤動作は.bashrc、行に追加することで修正できますset +H!スクリプトでは既に特別ではないことに注意してください。特別なものとして扱うと、多くの標準に準拠したスクリプトが壊れます。対話型シェルでは「特別」としてのみ扱われ、修正するまでデフォルトでのみ扱われます。:-)
R .. 14年

15

bashでは!予約語(OK、文字)であるため、さまざまなコンテキストで特別な意味を持ちます。この特定のケースでは、履歴検索でその重要性に違反しています。からman bash

   History expansions introduce words from the history list into the input
   stream, making it easy to repeat commands, insert the  arguments  to  a
   previous command into the current input line, or fix errors in previous
   commands quickly.

  [...]

   History expansions are introduced by
   the appearance of the  history  expansion  character,  which  is  !  by
   default.   Only  backslash  (\) and single quotes can quote the history
   expansion character.

基本的に、これが意味するのは、bashが後に文字を取得し、!それらの文字で始まる最初のコマンドを見つけるために履歴を検索するということです。説明するよりも実証する方が簡単です。

$ echo foo
foo
$ !e
echo foo
foo

!始まる最初のコマンドに一致アクティブに履歴展開、eこれは以前に実行したecho foo後、再度実行されたが。だから、あなたが書いたとき"SYNC TIME!"、bashはを見て!"、で始まるコマンドの履歴を検索し"、失敗し、それについて文句を言いました。たとえば、を実行すると、同じエラーが発生する可能性があります!nocommandstartswiththis

感嘆符を印刷するには、次の2つの方法のいずれかでエスケープする必要があります。

echo 'Hello world!'
echo Hello world\!

6
echo Hello world!動作します---履歴の展開は空白によってトリガーされません
;

1
ただし、空白よりも感嘆符をエスケープする方が適切です。
Ehteshチョードリー

1
私は明示的に変更することも可能だと言うそうではなく、行動のガイド私をすることを好む@Rmano
Braiam

!POSIXも宣言しているように、は予約語です。しかし、そのようなステータスは、歴史の拡大における役割まったく関係がなく、二重引用符での扱いとは無関係であると確信しています。コマンド/パイプラインの終了ステータスを無効にするため、予約語であり、コマンドとして使用することはできません。他の予約語に特殊ではないが、-quotedコンテキストでない予約語なくれる特別扱い。bash!"$
エリアケイガン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.