Saya menyadari bahwa !
memiliki arti khusus pada baris perintah dalam konteks sejarah baris perintah, tetapi selain itu, dalam skrip runing tanda seru kadang-kadang dapat menyebabkan kesalahan penguraian.
Saya pikir itu ada hubungannya dengan event
, tetapi saya tidak tahu apa acara itu atau apa fungsinya. Meski begitu, perintah yang sama dapat berperilaku berbeda dalam situasi yang berbeda.
Contoh terakhir, di bawah ini, menyebabkan kesalahan; tetapi mengapa, ketika kode yang sama bekerja di luar substitusi perintah? .. menggunakan GNU bash 4.1.5
# This works, with or without a space between ! and p
{ echo -e "foo\nbar" | sed -nre '/foo/! p'
echo -e "foo\nbar" | sed -nre '/foo/!p'; }
# bar
# bar
# This works, works when there is a space between ! and p
var="$(echo -e "foo\nbar" | sed -nre '/foo/! p')"; echo "$var"
# bar
# This causes an ERROR, with NO space between ! and p
var="$(echo -e "foo\nbar" | sed -nre '/foo/!p')"; echo "$var"
# bash: !p': event not found
bash
command-history
quoting
Peter.O
sumber
sumber
protected
akan lebih tepat. (dilindungi oleh 'kutipan tunggal')var=$(…)
(tanpa tanda kutip ganda), dan itu akan berfungsi seperti (saya pikir) yang Anda harapkan. Ini masih “aman” karena nilai bagian dari tugas sederhana tidak tunduk kata membelah atau globbing (meskipun ini tidak mungkin benar dari tugas dilakukan melalui builtin (misalnyaexport
,local
, dll) di bawah semua kerang). Sayangnya, ini tidak melampaui penugasan sederhana karena tanda kutip ganda adalah cara untuk melindungi terhadap pemisahan kata dan penggumpalan sementara masih mendapatkan jenis ekspansi lain dalam konteks lain.Jawaban:
The
!
karakter memanggil substitusi sejarah bash. Ketika diikuti oleh string (seperti pada contoh Anda yang gagal) itu mencoba untuk memperluas ke peristiwa sejarah terakhir yang dimulai dengan string itu. Sama seperti$var
diperluas ke nilai string itu,!echo
akan diperluas ke perintah gema terakhir dalam riwayat Anda.Ruang adalah karakter yang melanggar dalam ekspansi seperti itu. Catatan pertama bagaimana ini akan bekerja dengan variabel:
Hal yang sama akan terjadi pada ekspansi sejarah. Karakter bang (
!
) dimulai dari urutan penggantian histori, tetapi hanya jika diikuti oleh string. Mengikutinya dengan spasi membuatnya menjadi bang bukan bagian dari urutan ganti.Anda dapat menghindari penggantian semacam ini untuk ekspansi variabel dan riwayat dengan menggunakan tanda kutip tunggal. Contoh pertama Anda menggunakan tanda kutip tunggal dan berjalan dengan baik. Contoh terakhir Anda ada dalam tanda kutip ganda dan dengan demikian bash memindai mereka untuk urutan ekspansi sebelum melakukan hal lain. Satu-satunya alasan yang pertama tidak tersandung adalah bahwa ruang adalah karakter istirahat seperti yang ditunjukkan di atas.
sumber
var=word; echo "test '$var'"; echo 'test "$var"'
Seperti yang sudah dikatakan oleh Caleb ,
!
digunakan untuk menjalankan substitusi sejarah bash.Jika seperti saya Anda merasa Anda tidak memerlukan fitur seperti itu, Anda dapat menonaktifkannya dengan memasukkan baris berikut di
~/.bashrc
:Saya tidak membutuhkannya karena riwayat dapat dipulihkan oleh panah atas dan Ctrl- rpencarian terbalik tambahan. Lihat halaman manual bash, bagian Perintah untuk Memanipulasi Sejarah untuk daftar pintasan terperinci.
sumber
!!
?set +H
dalam skrip bekerja dengan baik :) +1contoh pertama Anda:
dapat dikurangi menjadi
Dalam tanda kutip tunggal, semua karakter mempertahankan nilai literalnya. Dengan demikian
!
telah kehilangan makna khusus dan ekspansi sejarah tidak terbentuk sebelumnya.contoh kedua dan ketiga Anda:
dapat dikurangi menjadi
'! p'
dan'!p'
pada dasarnya adalah bagian dari string yang dikutip ganda.Dalam tanda kutip ganda, semua karakter melestarikan nilai-nilai literal mereka kecuali
$
,`
,\
dan!
.Itu menyiratkan kutipan tunggal
'! p'
dan'!p'
telah kehilangan makna khusus mereka (yaitu: tidak dapat melarikan diri!
) tetapi!
masih mempertahankan makna khusus sehingga ekspansi sejarah dilakukan.Namun, ketika
!
diikuti oleh karakter spasi, ekspansi sejarah tidak dilakukan.Mengutip dari
man bash
:sumber