Bashは一重引用符内の特殊文字を解釈します。

Bashは一重引用符内の特殊文字を解釈します。

予期せず、興味深い動作が発生しました。やや複雑な実行中に、Bashが文字を処理する方法の理解に基づいてはいけない状況に直面しました。

問題の小さな例:

$ arr=( "$(echo '1 && !/==/')" )
-bash: !/=: event not found

ここで何が起こっているのでしょうか?私が理解しているように、一重引用符は、Bashが何らかの拡張なしですべての文字を文字通り解釈するように強制すると見なされます。

バッシュを使う4.1.2。

編集:単純化されたコピーの問題。

答え1

bash は無効なイベントのエラーで終了します。

!あなたは恐ろしい記録の置き換え(二重引用符内の文字)のために詰まっています。を使用して無効にできますset +H。ところで、これはスクリプトでは発生しません。

readarray単語分割に関して(またはエイリアスmapfile)を使用できます。

readarray -t array < <(df -Ph ...)

答え2

より小さい例(ただし、小さくはありません)東部時間)、Bash 4.1で:

$ set -H
$ arr=( "$(echo '1 && !/==/' )" )
bash4.1: !/==/': event not found
$ arr=(  $(echo '1 && !/==/' )  )              # no error
$ 

バッシュ4.4から:

$ set -H
$ arr=( "$(echo '1 && !/==/' )" )              # no error
$ arr=(  $(echo '1 && !/==/' )  )              # no error
$ 

それは歴史的拡張いいえ、これはコマンドライン処理の最初に発生し、それまでコマンド全体が解析されません。

履歴拡張は行全体を読むとすぐに実行され、次にシェルによって単語に分割され、各行で個別に実行されます。

なぜこれがうまくいくのか、なぜ二重引用符が影響するのかはよくわかりませんが、私が聞いたことを覚えている歴史的拡張に関するバグはこれだけではありません。

set +H履歴拡張を有効または無効にすることset +o histexpandができ、スクリプトではデフォルトで有効になっていません。

また、Bash 4.1は10年を超え、Bash 4.4(最後のバージョン番号は4.x)も2016年にリリースされました。 4.1以降、その他のバグが修正され、便利な機能が追加されました。

関連情報