Kenapa
grep e\\.g\\. <<< "this is an e.g. wow"
dan
grep e\.g\. <<< "this is an e.g. wow"
melakukan hal yang sama?
Jika saya menambahkan garis miring ketiga, hasilnya juga sama. TETAPI, setelah saya menambahkan tebasan keempat, itu tidak lagi berfungsi. Ini ada hubungannya dengan pertanyaan dari ujian lama untuk kelas. Ia bertanya apakah yang dengan dua backslash satu akan bekerja untuk menghasilkan garis dengan "misalnya" Saya awalnya berpikir itu tidak akan berhasil, tetapi saya mencoba untuk memastikan dan ternyata berhasil. Apa penjelasannya?
bash
shell
regular-expression
quoting
Wyatt Grant
sumber
sumber
\\\.
dan memberi grep\.
tetapi tidak. pertanyaan yang bagusJawaban:
Pertama, perhatikan bahwa slash tunggal terlalu cocok:
Sejauh menyangkut Bash , periode yang lolos sama dengan periode. Bash lolos pada periode untuk Grep . Untuk grep, suatu periode cocok dengan apa pun.
Sekarang, pertimbangkan:
Ketika Bash melihat double-slash, menguranginya menjadi tebasan tunggal dan meneruskannya ke grep yang, dalam tes pertama dari tiga tes di atas, melihat, seperti yang kita inginkan, tebasan tunggal sebelum periode. Jadi, ini melakukan hal yang benar.
Dengan tebasan tiga kali lipat, Bash mengurangi dua tebasan pertama menjadi tebasan tunggal. Kemudian ia melihat
\.
. Karena periode yang lolos tidak memiliki arti khusus untuk Bash, ini direduksi menjadi periode yang sederhana. Hasilnya adalah grep melihat, seperti yang kita inginkan, garis miring sebelum titik.Dengan empat tebasan, Bash mengurangi setiap pasangan menjadi tebasan tunggal. Bash meneruskan untuk meraih dua garis miring dan satu periode. grep melihat dua garis miring dan periode dan mengurangi dua garis miring ke satu literal slash. Kecuali jika input memiliki garis miring yang diikuti oleh karakter apa pun, tidak ada kecocokan.
Untuk menggambarkan yang terakhir, ingatlah bahwa di dalam tanda kutip tunggal, semua karakter adalah literal. Dengan demikian, mengingat tiga baris input berikut, perintah grep hanya cocok pada baris dengan slash literal pada input:
Ringkasan perilaku Bash
Untuk Bash, aturannya adalah
Dua garis miring dikurangi menjadi satu garis miring.
Garis miring di depan karakter normal, seperti titik, hanyalah karakter normal (titik).
Jadi:
Ada cara sederhana untuk menghindari semua kebingungan ini: pada baris perintah Bash, ekspresi reguler harus ditempatkan dalam tanda kutip tunggal. Di dalam tanda kutip tunggal, Bash meninggalkan semuanya sendirian.
sumber
echo
pernyataan yang menggambarkan apa yang dilakukan bash dalam kasus ini.\.
atau.
. Untuk bash, keduanya sama: keduanya setara dengan periode sederhana. Karenanya, secara total, apa yang dikirimkan bash ke grep adalah sama untuk keduanya: tebasan tunggal diikuti oleh suatu periode.echo
cara tidak bisa diandalkan untuk menguji regexp karena banyak implementasi program ini. Misalnya di bawah zsh saya (built-in echo)echo \. \\. \\\. \\\\. \\\\\.
memberi. \. \. \. \.
, tetapi/bin/echo \. \\. \\\. \\\\. \\\\\.
kembali. \. \. \\. \\.
. Sesuatu sepertiprintf "%s" ...
mungkin cara yang lebih baik.Outputnya sama hanya untuk string Anda, tetapi secara umum ekspresi reguler itu melakukan hal yang berbeda. Mari kita sedikit modifikasi contoh Anda dengan menambahkan pola kedua
e,g,
(dengan koma), ketigae\.g\.
(titik), keempate\,g\,
(koma), dan-o
opsi untuk grep untuk mencetak hanya bagian yang cocok.Dalam kasus berikut
.
cocok dengan char apa pun (perhatikan''
sekitare.g.
, saya akan datang untuk itu nanti)Selanjutnya kita melarikan diri
.
dengan backslash\
, jadi hanya literal yang.
akan cocok:Tetapi kita dapat melarikan diri
\
dengan yang lain\
, sehingga literal\
akan dicocokkan diikuti oleh.
(yaitu setiap karakter):Tetapi jika kita ingin mencocokkan hanya
\.
belum\,
maka yang lain\
diperlukan untuk melarikan diri makna khusus dari titik:Sekarang, karena Anda tidak menggunakan
''
argumen grep, Anda perlu menambahkan backslash lain untuk menghindari backslash dari interpretasi shell, jadi:sumber
Ketika Anda melakukan
grep e\.g\.
, shell mengkonsumsi backslash, sehingga Anda melakukangrep e.g.
, yang cocok. Saat Anda melakukangrep e\\.g\\.
, shell kembali mengkonsumsi garis miring, dan sekarang Anda melakukangrep e\.\g.
, yang lagi-lagi cocok. Sekarang, garis miring terbalik ke shell terlihat seperti\\
. Jadi, ketika Anda memilikinya\\
, yang pertama adalah urutan pelarian, yang kedua adalah backslash literal. Ketika Anda melakukangrep e\\\.g\\\.
, itu masih berakhir menjadigrep e\.\g.
, karena tidak ada urutan pelarian (\
) sebelum yang pertama\
untuk membuatnya menjadi literal\
. Perlu diingat \ adalah garis miring terbalik, sehinggagrep e\\\\.\\\\g
akhirnya menjadigrep e\\.g\\.
, yang jelas tidak cocok.Untuk melihat bagaimana shell melihat apa yang Anda lakukan, gunakan echo (mis.
echo grep e\\.g\\. <<< "this is an e.g. wow"
Vs.echo grep e\\\\.g\\\\. <<< "this is an e.g. wow"
)sumber
Kedua perintah menghasilkan output yang sama hanya untuk input Anda tetapi sebaliknya mereka berbeda. Untuk memahami apa yang sedang terjadi kita harus tahu bagaimana parameter ditafsirkan pertama kali oleh
bash
dan kemudian olehgrep
.Lolos dalam bash
\
adalah karakter khusus yang membatalkan arti khusus dari karakter berikut termasuk\
dirinya sendiri. Jika karakter berikut tidak memiliki arti khusus maka dilewatkan tanpa perubahan. Contoh dengan perintah dan hasil:echo \a
:a
- karakter biasa lolos memberikan karakterecho \\
:\
- karakter khusus lolos memberikan karakterecho \\\a
:\a
- kombinasi spesial, biasaecho \\\\
:\\
- kombinasi spesial, spesialecho
akan mencetak string yang dihasilkan setelahbash
mengartikannya. Informasi lebih lanjut: dokumentasi pesta , pesta hacker wiki , POSIX spesifikasi ..
tidak memiliki arti khusus dalambash
. Ini adalah karakter biasa untuk shell. Di bawah ini adalah urutan yang relevan dengan contoh Anda:echo .
:.
echo \.
:.
echo \\.
:\.
echo \\\.
:\.
echo \\\\.
:\\.
Solusi sederhana untuk string literal di bash
Untuk melewati parameter secara harfiah,
bash
Anda dapat menggunakan satu petik yang'
lolos. Di antara kutipan tunggal, Anda tidak perlu memedulikan arti khusus karakter karena kutipan tunggal adalah satu-satunya karakter dengan makna khusus di sana. Anda dapat memasukkan satu kutipan setelah melampirkan bagian pertama dari string. Contohecho 'part1'\''part2'
::part1'part2
Regex dalam grep
\
adalah karakter escape dengan arti yang sama seperti dibash
..
adalah karakter khusus yang mewakili kemunculan tunggal karakter apa pun . Lihat: POSIX regex , GNU grep regex . Contoh ekspresi regex:.
- cocok dengan karakter sepertia
atau.
\.
- hanya cocok.
secara harfiahContoh Anda
Pada baris kedua setiap contoh di bawah ini Anda akan menemukan setara dengan satu kutipan
'
menunjukkan yang string literal dilewatkan olehbash
untukgrep
. Kemudian setelahgrep
melakukan pelarian satu-satunya karakter khusus yang mungkin dalam contoh adalah.
mencocokkan karakter apa pun. Di baris ketiga ada deskripsi yang cocok dengan ekspresi itu.grep e.g. <<< "this is an e.g. wow"
grep 'e.g.' <<< "this is an e.g. wow"
e
karakterg
apa saja karakter apa saja - cocoke.g.
dan mungkin string lain sepertieagb
grep e\.g\. <<< "this is an e.g. wow"
grep 'e.g.' <<< "this is an e.g. wow"
e
karakterg
apa saja karakter apa saja - cocoke.g.
dan mungkin string lain sepertiexgy
grep e\\.g\\. <<< "this is an e.g. wow"
grep 'e\.g\.' <<< "this is an e.g. wow"
e.g.
secara harfiah - hanya cocoke.g.
grep e\\\.g\\\. <<< "this is an e.g. wow"
grep 'e\.g\.' <<< "this is an e.g. wow"
e.g.
secara harfiah - hanya cocoke.g.
grep e\\\\.g\\\\. <<< "this is an e.g. wow"
grep 'e\\.g\\.' <<< "this is an e.g. wow"
e\
karakterg\
apa pun karakter apa saja - tidak cocoke.g.
sumber