Apakah ada daftar karakter lengkap yang perlu diloloskan di Bash? Bisakah diperiksa hanya dengansed
?
Secara khusus, saya sedang memeriksa apakah %
perlu melarikan diri atau tidak. Saya mencoba
echo "h%h" | sed 's/%/i/g'
dan bekerja dengan baik, tanpa melarikan diri %
. Apakah itu berarti%
tidak perlu melarikan diri? Apakah ini cara yang baik untuk memeriksa keperluannya?
Dan lebih umum: mereka karakter yang sama untuk melarikan diri di shell
dan bash
?
Jawaban:
Ada dua aturan mudah dan aman yang berfungsi tidak hanya di dalamnya
sh
tetapi jugabash
.1. Masukkan seluruh string dalam tanda kutip tunggal
Ini berfungsi untuk semua karakter kecuali kutipan tunggal itu sendiri. Untuk menghindari kutip tunggal, tutup kutipan sebelumnya, masukkan kutip tunggal, dan buka kembali kutipan.
perintah sed:
sed -e "s/'/'\\\\''/g; 1s/^/'/; \$s/\$/'/"
2. Melarikan diri setiap char dengan backslash
Ini berfungsi untuk semua karakter kecuali baris baru. Untuk karakter baris baru gunakan tanda kutip tunggal atau ganda. String kosong masih harus ditangani - ganti dengan
""
perintah sed:
sed -e 's/./\\&/g; 1{$s/^$/""/}; 1!s/^/"/; $!s/$/"/'
.2b. Versi 2 yang lebih mudah dibaca
Ada serangkaian karakter yang aman dan mudah, seperti
[a-zA-Z0-9,._+:@%/-]
, yang dapat dibiarkan tanpa hambatan agar lebih mudah dibacaperintah sed:
LC_ALL=C sed -e 's/[^a-zA-Z0-9,._+@%/-]/\\&/g; 1{$s/^$/""/}; 1!s/^/"/; $!s/$/"/'
.Perhatikan bahwa dalam program sed, seseorang tidak dapat mengetahui apakah baris input terakhir berakhir dengan byte baris baru (kecuali ketika kosong). Itu sebabnya kedua perintah sed di atas menganggap itu tidak. Anda dapat menambahkan baris baru yang dikutip secara manual.
Perhatikan bahwa variabel shell hanya didefinisikan untuk teks dalam arti POSIX. Memproses data biner tidak ditentukan. Untuk implementasi yang penting, biner bekerja dengan pengecualian byte NUL (karena variabel diimplementasikan dengan string C, dan dimaksudkan untuk digunakan sebagai string C, yaitu argumen program), tetapi Anda harus beralih ke lokal "biner" seperti latin1 .
(Anda dapat dengan mudah memvalidasi aturan dengan membaca spesifikasi POSIX
sh
. Untuk bash, periksa manual referensi yang ditautkan oleh @AustinPhillips)sumber
sed
, tetapi membutuhkanbash
.format yang dapat digunakan kembali sebagai input shell
Ada arahan format khusus
printf
(%q
) yang dibuat untuk permintaan semacam ini:Beberapa sampel:
Ini dapat digunakan melalui variabel juga:
Pemeriksaan cepat dengan semua (128) byte ascii:
Perhatikan bahwa semua byte dari 128 hingga 255 harus di-escape.
Ini harus membuat sesuatu seperti:
Di mana bidang pertama adalah nilai hexa byte, berisi kedua
E
jika karakter harus di-escape dan field ketiga menampilkan lolos dari karakter.Mengapa
,
?Anda dapat melihat beberapa karakter yang tidak selalu harus diloloskan, seperti
,
,}
dan{
.Jadi tidak selalu tetapi kadang-kadang :
atau
tapi peduli:
sumber
subprocess.Popen(['bash', '-c', 'printf "%q\0" "$@"', '_', arbitrary_string], stdin=subprocess.PIPE, stdout=subprocess.PIPE).communicate()
akan memberi Anda versi shell yang dikutip dengan benararbitrary_string
.%q
rusak untuk waktu yang lama - Jika pikiran saya melayani saya dengan baik, kesalahan telah diperbaiki (tapi mungkin masih rusak) pada 2013 setelah rusak selama ~ 10 tahun. Jadi jangan mengandalkan itu.shlex.quote()
(> = 3.3,pipes.quote()
- tidak berdokumen - untuk versi yang lebih lama) juga akan melakukan pekerjaan dan menghasilkan versi yang lebih dapat dibaca manusia (menambahkan kutipan dan melarikan diri, jika perlu) dari sebagian besar string, tanpa perlu menelurkan shell.,
. Saya terkejut mengetahui bahwa bawaan Bashprintf -- %q ','
memberi\,
, tetapi/usr/bin/printf -- %q ','
memberi,
(tanpa escrow). Sama untuk karakter lainnya:{
,|
,}
,~
.Untuk menyelamatkan orang lain dari keharusan ke RTFM ... di bash :
... jadi jika Anda lolos dari itu (dan kutipannya sendiri, tentu saja) Anda mungkin baik-baik saja.
Jika Anda mengambil pendekatan yang lebih konservatif 'ketika ragu-ragu, lepas dari itu', Anda harus menghindari karakter yang memiliki makna khusus dengan tidak melarikan diri dari karakter pengidentifikasi (mis., Huruf ASCII, angka, atau '_'). Sangat tidak mungkin ini akan pernah (yaitu dalam beberapa shell POSIX-ish aneh) memiliki arti khusus dan dengan demikian perlu melarikan diri.
sumber
Dengan menggunakan
print '%q'
teknik ini , kita dapat menjalankan loop untuk mengetahui karakter mana yang spesial:Ini memberikan hasil ini:
Beberapa hasil, seperti
,
terlihat agak mencurigakan. Akan menarik untuk mendapatkan input @ CharlesDuffy tentang ini.sumber
,
terlihat sedikit curiga pada paragraf terakhir jawaban saya%q
Anda tidak tahu di mana di dalam shell Anda berencana untuk menggunakan karakter, jadi itu akan luput dari semua karakter yang dapat memiliki makna khusus dalam setiap konteks shell yang mungkin.,
itu sendiri tidak memiliki arti khusus untuk dia shell tetapi sebagai @ F.Hauri telah menunjukkan dalam jawabannya, itu memang memiliki makna khusus dalam{...}
ekspansi brace: gnu.org/savannah-checkouts/gnu/bash/manual/… Ini seperti! yang juga hanya membutuhkan ekspansi dalam situasi tertentu, tidak secara umum:echo Hello World!
berfungsi dengan baik, namunecho test!test
akan gagal.Karakter yang perlu melarikan diri berbeda di shell Bourne atau POSIX dari Bash. Umumnya (sangat) Bash adalah superset dari kerang-kerang itu, jadi apa pun yang Anda lewatkan
shell
harus dilepaskan di Bash.Aturan umum yang bagus adalah "jika ragu-ragu, hindarilah". Tetapi melarikan diri beberapa karakter memberi mereka makna khusus, seperti
\n
. Ini tercantum diman bash
halaman di bawahQuoting
danecho
.Selain itu, lepas dari karakter apa pun yang bukan alfanumerik, itu lebih aman. Saya tidak tahu daftar tunggal yang pasti.
Halaman manual mencantumkan semuanya di suatu tempat, tetapi tidak di satu tempat. Belajar bahasa, itu cara untuk memastikan.
Salah satu yang menarik saya adalah
!
. Ini adalah karakter khusus (ekspansi sejarah) di Bash (dan csh) tetapi tidak di shell Korn. Bahkanecho "Hello world!"
memberi masalah. Menggunakan tanda kutip tunggal, seperti biasa, menghilangkan makna khusus.sumber
sed
cukup baik untuk melihat apakah harus lolos. Terima kasih atas jawaban anda!sed
tidak perlu, Anda dapat memeriksa dengan hampir semua hal.sed
bukan masalahnya,bash
adalah. Di dalam tanda kutip tunggal tidak ada karakter khusus (kecuali tanda kutip tunggal), Anda bahkan tidak dapat melarikan diri karakter di sana. Sebuahsed
perintah biasanya harus berada di dalam tanda kutip tunggal karena metakarakter RE memiliki terlalu banyak tumpang tindih dengan metakarakter shell aman. Pengecualian adalah ketika menanamkan variabel shell, yang harus dilakukan dengan hati-hati.echo
. Jika Anda mendapatkan apa yang Anda masukkan, itu tidak perlu melarikan diri. :)Saya kira Anda berbicara tentang string bash. Ada beberapa tipe string yang memiliki serangkaian persyaratan berbeda untuk melarikan diri. misalnya. String kutipan tunggal berbeda dengan string kutipan ganda.
Referensi terbaik adalah Quoting manual bash.
Ini menjelaskan karakter mana yang harus diloloskan. Perhatikan bahwa beberapa karakter mungkin perlu keluar tergantung pada opsi mana yang diaktifkan seperti ekspansi riwayat.
sumber
Saya perhatikan bahwa bash secara otomatis keluar dari beberapa karakter saat menggunakan pelengkapan otomatis.
Misalnya, jika Anda memiliki direktori yang bernama
dir:A
, bash akan otomatis dilengkapi kedir\:A
Menggunakan ini, saya menjalankan beberapa percobaan menggunakan karakter dari tabel ASCII dan membuat daftar berikut:
Karakter yang kabur lolos pada lengkapi-otomatis : (termasuk spasi)
Karakter yang bash tidak luput :
(Saya mengecualikan
/
, karena tidak dapat digunakan dalam nama direktori)sumber
printf %q
tidak dan tidak dimodifikasi jika dilewatkan sebagai argumen - idealnya, melalui seluruh rangkaian karakter.