Mengapa `echo -e“ \\ SOME_TEXT ”` hanya menampilkan satu garis miring terbalik?

19

Bisakah seseorang menjelaskan apa yang terjadi di balik layar dalam karakter melarikan diri di shell Linux? Saya mencoba yang berikut ini dan sering googled, tanpa berhasil memahami apa (dan bagaimana) yang terjadi:

root@sv01:~# echo -e "\ Hello!"
\ Hello!
root@sv01:~# echo -e "\\ Hello!"
\ Hello!
root@sv01:~# echo -e "\\\ Hello!"
\ Hello!
root@sv01:~# echo -e "\\\\ Hello!"
\ Hello!
root@sv01:~# echo -e "\\\\\ Hello!"
\\ Hello!
root@sv01:~# echo -e "\\\\\\ Hello!"
\\ Hello!
root@sv01:~# echo -e "\\\\\\\ Hello!"
\\ Hello!
root@sv01:~# echo -e "\\\\\\\\ Hello!"
\\ Hello!
root@sv01:~# echo -e "\\\\\\\\\ Hello!"
\\\ Hello!
root@sv01:~# echo -e "\n Hello!"

 Hello!
root@sv01:~# echo -e "\\n Hello!"

 Hello!
root@sv01:~# echo -e "\\\n Hello!"
\n Hello!

Saya benar-benar tersesat di sana, jadi misalnya, mengapa tiga garis miring terbalik hanya memberikan satu tebasan belakang? Saya berharap: dua yang pertama akan lolos ke satu, yang ketiga tidak akan menemukan apa pun untuk melarikan diri sehingga akan tetap menjadi garis miring (garis dalam percobaan pertama), tetapi yang terjadi adalah bahwa yang ketiga hilang begitu saja.
Mengapa saya mendapatkan satu backslash dari empat \\\\ Hello? Saya berharap setiap pasangan akan memberikan satu tebasan -> dua garis miring terbalik.

Dan mengapa saya perlu tiga backslash dalam kasus terakhir untuk bisa lolos? apa yang terjadi di latar belakang melarikan diri untuk mendapatkan itu? dan apa bedanya dengan \\ncase?

Saya menghargai penjelasan apa pun yang terjadi di baris sebelumnya.

Mohammed Noureldin
sumber
echo -eperilaku bukanlah standar yang ditentukan - lihat pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html . Keluaran sepenuhnya ditentukan oleh implementasi jika ada backslash literal di mana saja dalam input, dan satu-satunya opsi yang diizinkan adalah -n(artinya implementasi yang sesuai standar akan echo -emencetak -epada outputnya).
Charles Duffy
... bahkan jika Anda 100% yakin bahwa shell Anda bash, itupun echo -e tidak aman: echoakan berperilaku sesuai dengan standar jika keduanya posixdan xpg_echoopsi runtime diaktifkan, atau jika dikompilasi dengan opsi waktu-bangun yang setara. Praktik yang aman adalah menggunakan printfsebagai gantinya - lihat bagian APLIKASI PENGGUNAAN dan RATIONALE dari tautan di atas yang menjelaskan cara menjadikan printftindakan sebagai pengganti echo.
Charles Duffy

Jawaban:

28

Ini karena bashdan echo -edigabungkan. Dariman 1 bash

Garis miring terbalik ( \) adalah karakter pelarian. Ini mempertahankan nilai literal dari karakter berikutnya yang mengikuti, dengan pengecualian <newline>. [...]

Melampirkan karakter dalam tanda kutip ganda mempertahankan nilai literal dari semua karakter dalam tanda kutip, dengan pengecualian $, `, \, [...] backslash mempertahankan arti khusus hanya ketika diikuti oleh salah satu karakter berikut: $,`, ", \, atau <newline>.

Intinya adalah: backslash yang dikutip ganda tidak selalu spesial.

Ada berbagai implementasi echopada umumnya, ini adalah builtin in bash; yang penting di sini adalah perilaku ini:

Jika -eini berlaku, urutan berikut diakui:
\\
backslash
[...]
\n
baris baru

Sekarang kita dapat memecahkan kode:

  1. echo -e "\ Hello!"- tidak ada yang istimewa bash, tidak ada yang istimewa untuk echo; \tetap.
  2. echo -e "\\ Hello!"- Yang pertama \mengatakan bashuntuk memperlakukan yang kedua \secara harfiah; echodapatkan \ Hello!dan bertindak seperti di atas.
  3. echo -e "\\\ Hello!"- Yang pertama \mengatakan bashuntuk memperlakukan yang kedua \secara harfiah; echomendapat \\ Hello!dan (karena -e) itu diakui \\sebagai \.
  4. echo -e "\\\\ Hello!"- Yang pertama \mengatakan bashuntuk memperlakukan yang kedua \secara harfiah; yang ketiga mengatakan hal yang sama tentang yang keempat; echomendapat \\ Hello!dan (karena -e) itu diakui \\sebagai \.
  5. echo -e "\\\\\ Hello!"- Yang pertama \mengatakan bashuntuk memperlakukan yang kedua \secara harfiah; yang ketiga mengatakan hal yang sama tentang yang keempat; yang terakhir tidak spesial; echomendapat \\\ Hello!dan (karena -e) ia mengenali inisial \\sebagai \, yang terakhir \tetap utuh.

Dan seterusnya. Seperti yang Anda lihat, hingga empat garis miring terbalik berturut-turut memberikan satu dalam hasil. Itu sebabnya Anda perlu (setidaknya) sembilan dari mereka untuk mendapatkan tiga. 9 = 4 + 4 + 1.

Sekarang dengan \n:

  1. echo -e "\n Hello!"- tidak ada yang istimewa bash, gema mendapatkan string yang sama dan (karena -e) ia mengartikan \nsebagai baris baru.
  2. echo -e "\\n Hello!"- bashmenafsirkan \\sebagai \; echodapatkan \n Hello!dan hasilnya sama seperti di atas.
  3. echo -e "\\\n Hello!"- bashMenafsirkan inisial \\sebagai \; echomendapat \\n Hello!dan (karena -e) mengartikannya \\sebagai literal \yang perlu dicetak.

Hasilnya akan berbeda dengan 'bukan "(karena bashperilaku yang berbeda ) atau tanpa -e( echoperilaku yang berbeda ).

Kamil Maciorowski
sumber
1
Terima kasih banyak! Jadi ada dua langkah melarikan diri, langkah dilakukan oleh bash, dan yang kedua dengan -emenilai teks yang sudah dinilai oleh bash, benarkah itu? jika itu benar, itu menghilangkan kebingungan. Bisakah Anda menyebutkan bagaimana sedberperilaku? apakah ia memiliki teknik pelariannya sendiri? jadi maksud saya apakah itu berperilaku seperti gema -e?
Mohammed Noureldin
2
@MohammedNoureldin Ya, ada dua langkah. Pertanyaan awal Anda baik-baik saja, jangan dibuat terlalu rumit sed. Anda dapat mengajukan pertanyaan lain ( sedhanya tentang ), lakukan penelitian Anda sendiri terlebih dahulu.
Kamil Maciorowski
3
@MohammedNoureldin sedakan mengikuti prinsip-prinsip dasar yang sama: bash akan menginterpretasikan baris perintah sesuai dengan aturannya, mengurai (dan mungkin menghapus) tanda kutip dan lolos. Hasil itu diteruskan sed, yang menafsirkannya sesuai dengan aturan pelariannya. BTW, Anda dapat menyederhanakan ini dengan menggunakan string dengan tanda kutip tunggal bash, karena itu tidak memiliki interpretasi melarikan diri dilakukan (oleh bash) - bash menghapus tanda kutip tunggal, dan meneruskan apa yang ada di dalamnya langsung ke perintah.
Gordon Davisson
Saya masih punya masalah kecil dalam echo -e "\\\n Hello!"kasus ini. Di sini bash akan melarikan diri, dan itu akan menjadi \\n, kemudian -eakan lolos dari dua backslash yang dihasilkan \\ndan kemudian mereka akan menjadi \n. sekarang siapa yang mengartikan \nuntuk membuatnya menjadi baris baru? Biasanya dalam kasus echo -e "\n Hello!", bash tidak melakukan apa-apa, dan -emenafsirkan \nsebagai baris baru. tetapi dalam situasi yang disebutkan pertama proses penafsiran dilakukan sebelum \nditafsirkan. Bisakah Anda jelaskan itu?
Mohammed Noureldin
1
Ok salahku, aku sudah membaca tentang itu selama 2 hari dengan malam-malam mereka, oleh karena itu rupanya aku mulai mencampur kasing, aku percaya aku punya sesuatu yang lain sedyang membingungkanku tadi malam (mungkin aku melakukan sesuatu yang salah kemarin), tapi sekarang aku mencoba lagi sama dengan echo -edan sed, dan saya mendapat hal yang sama seperti dikecualikan, terima kasih!
Mohammed Noureldin