Apa itu "-bash:!": Acara tidak ditemukan "

114

Coba jalankan yang berikut di bawah bash shell echo "Reboot your instance!"

Pada instalasi saya:

root@domU-12-31-39-04-11-83:/usr/local/bin# bash --version
GNU bash, version 4.1.5(1)-release (i686-pc-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
root@domU-12-31-39-04-11-83:/usr/local/bin# uname -a
Linux domU-12-31-39-04-11-83 2.6.35-22-virtual #35-Ubuntu SMP Sat Oct 16 23:57:40 UTC 2010 i686 GNU/Linux
root@domU-12-31-39-04-11-83:/usr/local/bin# echo "Reboot your instance!"
-bash: !": event not found

Adakah yang bisa menjelaskan apa itu "bash events?" Saya belum pernah mendengar konsep ini sebelumnya. Juga, bagaimana saya harus menampilkan "!" di akhir kalimat?

Maxim Veksler
sumber

Jawaban:

53

Anda dapat mematikan subtitusi riwayat menggunakan set +H.

Dennis Williamson
sumber
2
Apakah Anda tahu alasan di balik sintaks? Tampaknya sangat kontra intuitif. Anda akan berpikir Anda mengetik +Huntuk mengaktifkan sesuatu dan -Hmenonaktifkan sesuatu.
Gavin Ward
7
@ PunkyGuy: Saya tidak tahu sejarah (pun intended) di belakangnya, tetapi opsi Unix biasanya dimulai dengan tanda hubung (atau minus) dan +merupakan kebalikan dari itu.
Dennis Williamson
105

!adalah karakter khusus untuk bash, digunakan untuk merujuk ke perintah sebelumnya; misalnya,

!rm

akan mengingat dan menjalankan perintah terakhir yang dimulai dengan string "rm", dan

!rm:p

akan mengingat tetapi tidak menjalankan perintah terakhir yang dimulai dengan string "rm". bash mengartikan tanda seru echo "reboot your instance!"sebagai " gantikan di sini perintah terakhir yang dimulai dengan karakter (s) segera setelah tanda seru ", dan mengomel pada Anda bahwa itu tidak dapat menemukan suatu peristiwa (perintah) dalam sejarah Anda yang dimulai dengan satu kutipan ganda.

Mencoba

echo reboot your instance\!

untuk melindungi (melarikan diri) tanda seru dari bash.

MadHatter
sumber
Ya, tetapi harus terjadi jika saya ingin menggunakan echo -e "beberapa teks $ ENV_VAL beberapa teks lagi \ nBooting sekarang!" ?
Maxim Veksler
1
Tulis dua pernyataan gema; Anda mendapatkan linefeed gratis.
MadHatter
1
Solusi sederhana adalah dengan menggunakan tanda kutip tunggal dan ganda sekaligus: echo -e "Text \ nReeboot" '!'
mmey
4
Ini menyebalkan. Jika saya tidak luput dari tanda seru, bash cocok. Jika saya berhasil menghindarinya, garis miring terbalik termasuk dalam string terakhir. Mengapa kamu melakukan ini, Bash !! ( pastebin.com/g4PYv56A )
Hubro
2
@Hubro dalam keadilan, saya tidak yakin itu semua kesalahan bash. Anda memiliki masalah yang agak rumit dengan menggunakan ruby ​​untuk memberi makan hal-hal untuk dihancurkan, dan bagi saya tidak jelas bagian apa yang dimainkan ruby ​​dalam stripping atau penguatan karakter pelarian.
MadHatter
25

Untuk mengatasi masalah awal Anda, coba gunakan tanda kutip tunggal, bukan tanda kutip ganda. Dengan yang terakhir, bash akan mencoba untuk memperluas karakter tertentu sebelum meneruskan hasilnya ke perintah (gema dalam kasus ini). Dengan tanda kutip tunggal, bash melewati seluruh string, tidak berubah.

!digunakan dalam perintah untuk merujuk ke sejarah baris perintah. Lihat: http://tldp.org/LDP/abs/html/abs-guide.html#HISTCOMMANDS untuk set lengkap. Dengan contoh di atas, bash mencoba untuk memperluas !"sebagai referensi ke suatu peristiwa sebelum gema masuk, maka kesalahannya.

Perhatikan bahwa dalam skrip, semua perintah riwayat dinonaktifkan, karena hanya masuk akal di shell interaktif.

Satu-satunya yang saya gunakan secara teratur, adalah !$. Itu memperluas argumen terakhir dari perintah sebelumnya. Ini adalah singkatan yang berguna di beberapa tempat.

SmallClanger
sumber
4
!!mengisi perintah terakhir lengkap yang dimasukkan sangat berguna; khususnya, sudo !!ataupfexec !!
jgoldschrafe
2
Saya juga menemukan sudo dan pfexec sebagai utilitas yang bagus, tetapi tidak perlu begitu antusias.
LeartS
$_bekerja di lebih banyak shell daripada bash dan ini adalah variabel yang tepat, tidak seperti !$. (dan @LeartS: Saya menyukai lelucon Anda tentang emotikon.;))
ΤΖΩΤΖΙΟΥ
7

Beri jarak saja! dan "daripada itu akan berhasil.

Tepuk tangan.

Isik Mater
sumber
2
Bisakah Anda menambahkan penjelasan mengapa solusi Anda berfungsi?
200_success
2
Ini bekerja karena Bash hanya memperlakukan! sebagai karakter khusus jika langsung diikuti oleh karakter non-spasi. Namun, itu juga akan menambah kosong ekstra untuk output Anda, sehingga mungkin tidak selalu diinginkan ...
mmey
2

Iya, ! adalah karakter khusus untuk bash, digunakan untuk merujuk ke perintah sebelumnya.

Beberapa cara Anda dapat menangani situasi

Berikut ini akan menampilkan string apa adanya

echo 'Reboot your instance!'

Berikut ini akan menjalankan perintah dan menyatukan string

echo 'escaping #'" adding `which python` to the string"
echo '#!'`which python`
Syed Qaiser
sumber
1

Di bash 4.3tampaknya Anda tidak perlu lagi menggunakan tanda kutip tunggal atau set +H:

$ bash --version
GNU bash, version 4.3.46(1)-release (x86_64-unknown-linux-gnu)
[...]
$ echo "Reboot your instance!"
Reboot your instance!
Eugene Yarmash
sumber
Mungkin bug, karena di sini, saya memiliki 4.4.12 dan lagi, saya perlu set +Hatau mengutip. Atau Anda punya set +Htempat (seperti di /etc/profile).
Bodo Thiesen
Menggunakan! -Char tidak di akhir kalimat memverifikasi deteksi acara bash masih berfungsi dengan baik. Versi adalah 4.3.30 ........ $ echo "Periksa kembali kalimat Anda! Foo" bash
:!
0

Anda juga bisa menggunakan heredoc :

cat <<EOF
Reboot your instance!
EOF

Ini menjengkelkan dalam kasus ini karena ini bukan satu-baris tetapi untuk perintah yang lebih lama (seperti menulis skrip bash), ini berfungsi dengan baik.

Tom Saleeba
sumber