Dalam bash, bagaimana saya bisa lolos dari tanda seru?

183

Saya ingin melakukan sesuatu seperti bzr commit -m "It works!". Saya bisa lolos dari tanda seru dengan melakukan bzr commit -m "It works\!". Namun, kemudian pesan komit saya menyertakan backslash. Bagaimana saya bisa lolos dari tanda seru, sementara masih mengabaikan garis miring terbalik?

Matius
sumber
1
Melakukan bzr commit -m "It works"!pekerjaan juga.
kba
1
Seperti yang saya catat sebelum perintah yang Anda masukkan benar-benar bekerja sendiri :)bzr commit -m "It works!"
h4unt3r
Kasus yang bahkan lebih aneh dengan kutipan bersarang: stackoverflow.com/questions/22125658/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
1
Meskipun jawaban yang diterima adalah solusi yang baik untuk masalah komit Anda, saya merasa itu bukan jawaban untuk masalah aktual: Perluasan sejarah bash . Tolong pertimbangkan untuk menerima jawaban Dennis?
Arjan

Jawaban:

153

Karena Anda tidak bergantung pada bash untuk memperluas variabel dalam pesan komit Anda, Anda bisa menggunakan tanda kutip tunggal. String dalam tanda kutip tunggal tidak diperluas oleh bash.

bzr commit -m 'This does work!' 
Benjamin Bannier
sumber
24
Karena pertanyaannya adalah "Bagaimana saya bisa lolos dari tanda seru?" dan bukan "Bagaimana saya tidak memperluas tanda seru?" Saya rasa ini tidak valid. Ada beberapa kali (seperti ketika melewati tanda kutip dan tanda seru di baris perintah yang sama) bahwa ini tidak berfungsi. Jawaban di bawah ini berfungsi lebih baik untuk melakukan apa yang dibutuhkan banyak orang.
Jann
7
@ Jan: Anda 100% benar dalam hal ini, tapi saya pikir masalahnya ada di sini adalah orang dengan begitu banyak pertanyaan tentang pengguna super: Apakah kita menjawab pertanyaan itu langsung, atau apakah kita membantu orang memecahkan masalah khusus mereka. Saya pikir kedua cara ini dapat bermanfaat, dan ini mencari bantuan untuk masalah tertentu.
Benjamin Bannier
sentuh! Ini adalah masalah khusus. Saya hanya cenderung ingin jawaban atas pertanyaan saya untuk dapat digunakan dalam banyak situasi. pS: Alasan saya bahkan menyebutkan ini adalah saya perlu melewati tanda kutip dan tanda seru untuk program perl dan saya membutuhkan solusi di bawah ini. :)
Jann
Saya setuju dengan Benjamin dan Jann tetapi memberikan suara rendah. Judul pertanyaan diindeks oleh mesin pencari dan itulah bagaimana saya datang ke sini dan mungkin sebagian besar pengguna datang ke sini. Itulah mengapa saya percaya bahwa pertanyaan aktual mencerminkan masalah di baliknya. Di forum lain orang disarankan (hampir dipaksa) untuk menanyakan dengan tepat apa yang mereka cari. Menjawab pertanyaan yang diungkapkan dengan buruk mendukung kecerobohan dan itulah alasan yang tepat untuk downvote saya di sini. Sebagai kompromi / solusi, saran saya adalah membantu menyesuaikan tajuk sehingga mencerminkan masalah yang sebenarnya.
ChristophK
153

Berikut adalah metode lain jika Anda ingin tanda kutip ganda serta tanda seru:

echo "It's broken"'!'

Ini berfungsi bahkan jika !tidak di akhir baris.

Misalnya:

echo "hello there"'!'" and goodbye"

Bonus: Teknik serupa dapat digunakan untuk menghindari teks apa pun di Sh atau Bash (dengan bantuan sed): lihat opsi pertama dalam jawaban ini . Selanjutnya, jika Anda telah bash-completionterinstal, Anda mungkin memiliki satu quote()fungsi yang tersedia sudah.

jwd
sumber
4
Tip yang bagus, JWD. Saya tidak menyadari string bash dapat digabungkan hanya dengan menghilangkan spasi putih di antara mereka.
Alan H.
Sebenarnya jika tanda seru berada di akhir string, Anda berada di tempat yang jelas echo "Happy birthday!"akan bekerja seperti yang diharapkan jika tidak, Anda dapat menghindarinya dengan backslash, tetapi backslash akan dicetak juga XD Bash bukan untuk yang lemah hati :)
h4unt3r
@ h4unt3r: Aneh, itu bukan pengalaman saya. Bagi saya, echo "Happy Birthday!"menghasilkan 2 baris. Yang pertama adalah echo "Happy birthday"(tidak ada seru), dan yang kedua adalah "Selamat ulang tahun" (sekali lagi, tidak ada seru). Apakah Anda memiliki ekspansi riwayat yang diaktifkan saat melakukan tes ini?
jwd
@ jwd bash versi apa yang Anda jalankan? Saya selalu memiliki ekspansi hist. Apakah Anda tidak sengaja menggunakan dua !! untuk ujianmu?
h4unt3r
@ h4unt3r:, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)pasti hanya satu !yang digunakan. Saya sudah histexpandhadir di $SHELLOPTS. Namun, saya baru saja mencoba 4.3.18 (2) -tanggalkan pada komputer lain, dan berperilaku seperti yang Anda gambarkan. Saya kira itu adalah bug yang diperbaiki.
jwd
66

Matikan ekspansi riwayat :

set +H

atau

set +o histexpand

Anda dapat menambahkan salah satu dari perintah itu ke Anda ~/.bashrcjika Anda biasanya tidak menggunakan ekspansi riwayat.

Bash 4.3 menambahkan kasus khusus :

karakter ekspansi sejarah juga diperlakukan seperti dikutip jika ia segera mendahului kutipan ganda penutup dalam string yang dikutip ganda

Dennis Williamson
sumber
Terima kasih - ini berhasil, tetapi saya harus melakukannya set +o histexpand, tidak set -o histexpand. Bisakah Anda mengedit jawaban Anda untuk memperbaikinya?
Matius
Ups, salah ketik, maaf. Tetap.
Dennis Williamson
sangat baik! sedang mencari ini untuk USIA .... thx vm! sebagai escape wont work ... Saya tidak ingin menggunakan tanda kutip tunggal juga ... Saya akan menambahkan ini ke .bashrcthx saya !!, tidak pernah digunakan !dalam skrip dan untuk apa-apa !! itu selalu menyusahkan ...
Aquarius Power
Ini luar biasa! echo "@AquariusPower!"
joehanna
12

Gunakan tanda kutip tunggal (') alih-alih tanda kutip ganda ("). Kutipan tunggal mematikan semua interpretasi barang di dalamnya, sedangkan tanda kutip ganda hanya mematikan sebagian.

bzr commit -m 'It works!'
KeithB
sumber
4

Saya baru saja menemukan cara lain, yang paling tidak akan berfungsi dengan echostring (kalimat) yang ingin Anda beri tanda baca dengan tanda seru. Itu menjalankan akhir, lebih atau kurang, sekitar Bash histexpand dan hanya butuh sedikit lebih lama untuk kode.

Hex untuk tanda seru, seperti yang tercantum di http://www.ascii-code.com/ , adalah 21, jadi jika Anda meletakkan \x21di akhir string Anda echo -e $foo,, buat $foogema yang diperluas sendiri [yaitu, foo=$(echo -e "$foo")], apa yang Anda dapatkan ketika Anda echo $foolagi adalah string dengan !di akhir. Dan tidak ada switching histexpand baik.

Bekerja pasti di Bash 4+. Versi sebelumnya, ymmv.

SilversleevesX
sumber
Hmmm itu tidak berhasil untuk saya.
lzap
Saya tidak mengerti apa yang Anda katakan tentang gema itu sendiri. Interpretasi 'echo -e' dan 'printf' lolos kode oktal, hex, dan Unicode. Dalam kasus di mana Anda menggunakan salah satu dari itu, Anda dapat menggunakan "\ 041" (oktal untuk "!") Atau "\ x21" (hex) untuk berdiri di titik seru. Sebagai contoh: printf "OMG\041". Jika Anda membuat string yang dikutip ganda di suatu tempat yang bukan echo atau printf, seperti yang dilakukan oleh string komit OP, Anda dapat menanamkan $(echo -e "\041")dalam string di mana tanda seru seharusnya. Seperti ini: bzr commit -m "This is a great commit$(echo -e "\041")".
Todd Walton