bashに !' で event no found と怒られた理由を考えてみる

  • 1
    いいね
  • 0
    コメント

先日の遭遇した下のエラーについて調べてみた。

$ ruby -e "puts 'Hello, World!'"
bash: !': event no found

「!」とは?

!に続く文字列に一致する最新のコマンドの再実行。
Bashでエクスクラメーションマークで始まるコマンドはどういう意味でしょうか... - Yahoo!知恵袋

Bashにはヒストリ展開という機能がある。
この機能によって、コマンド中の!fooのような文字列は、実行したことのあるfooから始まるコマンドの中で最も最近のものに置き換えられる。
[Bash] ダブルクォートで囲んだコマンド置換中で!を使うとエラーになる(例: echo "$(echo '!')") - Qiita

直近のコマンドを再実行されることが分かったので、ちょっと試してみる。

$ 'uname'
Linux
$ "arch"
x86_64

このコマンドを「!」で再実行

$ !'
'uname'
Linux
$ !"
"arch"
x86_64

なるほど

ということで

$ ruby -e "puts 'Hello, World!'"
bash: !': event no found

この原因はこのコマンド以前に「'」から始まるコマンドを実行していないから、エラーが発生したことを理解。

では、「'」から始まるコマンドがあった場合、どう処理されるのか?

$ 'uname'
Linux
$ ruby -e "puts 'Hello, World!'"
ruby -e "puts 'Hello, World'uname'"
-e:1: syntax error, unexpected tIDENTIFIER, expecting end-of-input
puts 'Hello, World'uname'
                        ^

'uname' が展開されて実行。そして、構文エラー

ちなみに、履歴を辿ると構文エラーのコマンドで残っている。(当然か)

$ ruby -e "puts 'Hello, World'uname'"

ただ、

$ ruby -e 'puts "Hello, World!"'
Hello, World!

こっちのパターン(!")で、展開されない理由が良く分からない…。
'' に囲まれていることによってエスケープされた?

おまけ

$ 'uname'
Linux
$ echo '!'
!
$ echo '"!"'
"!"
$ echo "'!'"
echo "''uname'"
''uname'

最後のコマンドの展開
" ' !' "
   ↓
" ' 'uname' "