Advanced Bash Regex dengan contoh
- 4020
- 1141
- Dale Harris II
Menggunakan kuasa ekspresi biasa, seseorang dapat menghuraikan dan mengubah dokumen dan rentetan berasaskan teks. Artikel ini adalah untuk Pengguna Lanjutan, yang sudah biasa dengan ungkapan biasa asas di Bash. Untuk pengenalan kepada ekspresi tetap bash, lihat ungkapan biasa kami untuk pemula dengan artikel contoh. Artikel lain yang anda dapati menarik adalah ungkapan biasa di Python.
Bersedia untuk Bermula? Menyelam dan belajar menggunakan regexps seperti pro!
Dalam tutorial ini anda akan belajar:
- Cara Menghindari Perbezaan Sistem Operasi Kecil daripada Mempengaruhi Ekspresi Biasa Anda
- Cara mengelakkan menggunakan penepuk carian ekspresi biasa yang terlalu generik seperti
.*
- Cara Menggaji, atau Tidak Menggaji, Sintaks Ekspresi Biasa yang Diperluas
- Contoh Penggunaan Lanjutan Ekspresi Biasa Kompleks di Bash
Keperluan perisian dan konvensyen yang digunakan
Kategori | Keperluan, konvensyen atau versi perisian yang digunakan |
---|---|
Sistem | Pengedaran linux-bebas |
Perisian | Baris perintah bash, sistem berasaskan linux |
Yang lain | Utiliti SED digunakan sebagai alat contoh untuk menggunakan ekspresi biasa |
Konvensyen | # - Memerlukan komando linux yang diberikan untuk dilaksanakan dengan keistimewaan akar sama ada secara langsung sebagai pengguna root atau dengan menggunakan sudo perintah$-memerlukan komando Linux yang diberikan sebagai pengguna yang tidak berkadar biasa |
Contoh 1: Menggalakkan menggunakan ekspresi biasa yang dilanjutkan
Untuk tutorial ini, kami akan menggunakan SED sebagai enjin pemprosesan ekspresi biasa kami. Sebarang contoh yang diberikan biasanya boleh dipindahkan terus ke enjin lain, seperti enjin ekspresi biasa yang termasuk dalam grep, awk dll.
Satu perkara yang perlu diingat semasa bekerja dengan ungkapan biasa, adalah bahawa beberapa enjin regex (seperti yang ada di sed) menyokong kedua -dua sintaks ekspresi biasa yang biasa dan dilanjutkan. Contohnya, SED akan membolehkan anda menggunakan -E
pilihan (pilihan singkat untuk --regexp-extended
), membolehkan anda menggunakan ekspresi tetap lanjutan dalam skrip sed.
Secara praktikal, ini menghasilkan perbezaan kecil dalam ungkapan sintaks ekspresi biasa semasa menulis skrip ekspresi biasa. Mari lihat contoh:
$ echo 'sampel' | sed's | [a-e] \+| _ | g 's_mpl_ $ echo' sampel '| sed 's | [a-e]+| _ | g' sampel $ echo 'sampel+' | sed 's | [a-e]+| _ | g' sampl_ $ echo 'sampel' | sed -E 's | [a -e]+| _ | g' s_mpl_
Seperti yang anda lihat, dalam contoh pertama kami kami gunakan \+
untuk melayakkan julat A-C (diganti secara global kerana g
Qualifier) Seperti yang memerlukan satu atau lebih kejadian. Perhatikan bahawa sintaks, khususnya, adalah \+
. Namun, ketika kita mengubahnya \+
ke +
, Perintah menghasilkan output yang sama sekali berbeza. Ini kerana +
tidak ditafsirkan sebagai watak plus standard, dan bukan sebagai perintah regex.
Ini kemudiannya dibuktikan oleh perintah ketiga di mana literal +
, serta e
Sebelum itu, ditangkap oleh ungkapan biasa [a-e]+
, dan berubah menjadi _
.
Melihat ke belakang bahawa perintah pertama, sekarang kita dapat melihat bagaimana \+
ditafsirkan sebagai ungkapan biasa bukan literal +
, akan diproses oleh sed.
Akhirnya, dalam perintah terakhir kami memberitahu SED bahawa kami secara khusus mahu menggunakan sintaks lanjutan dengan menggunakan -E
Pilihan sintaks yang dilanjutkan ke sed. Perhatikan bahawa istilah dilanjutkan memberi kita petunjuk tentang apa yang berlaku di latar belakang; sintaks ungkapan biasa adalah berkembang Untuk membolehkan pelbagai arahan regex, seperti dalam kes ini +
.
Sekali -E
digunakan, walaupun kita masih menggunakan +
dan tidak \+
, sed dengan betul menafsirkan +
sebagai arahan ungkapan biasa.
Apabila anda menulis banyak ungkapan biasa, perbezaan kecil ini dalam menyatakan pemikiran anda ke dalam ekspresi biasa memudar ke latar belakang, dan anda akan cenderung untuk mengingati yang paling penting.
Ini juga menyoroti keperluan untuk sentiasa menguji ungkapan biasa secara meluas, memandangkan pelbagai kemungkinan input, bahkan yang anda tidak harapkan.
Contoh 2: Pengubahsuaian rentetan tugas berat
Untuk contoh ini, dan yang berikutnya, kami telah menyediakan fail tekstual. Jika anda ingin berlatih bersama, anda boleh menggunakan arahan berikut untuk membuat fail ini sendiri:
$ echo 'abcdefghijklmnopqrstuvwxyz abcdefg 0123456789'> test1 $ Cat test1 abcdefghijklmnopqrstuvwxyz abcdefg 0123456789
Sekarang mari kita lihat contoh pertama kami mengenai pengubahsuaian rentetan: kami ingin lajur kedua (A B C D E F G
) untuk datang sebelum yang pertama (abcdefghijklmnopqrstuvwxyz
).
Sebagai permulaan, kami membuat percubaan fiksyen ini:
$ CAT TEST1 ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFG 0123456789 $ CAT TEST1 | sed -e 's | ([a -o]+).*([A-z]+) | \ 2 \ 1 | ' G ABCDEFGHIJKLMNO 0123456789
Adakah anda memahami ungkapan biasa ini? Jika ya, anda sudah menjadi penulis ekspresi biasa yang sangat maju, dan anda boleh memilih untuk melangkah ke contoh berikut, melangkah ke atas mereka untuk melihat sama ada anda dapat dengan cepat memahami mereka, atau memerlukan sedikit bantuan.
Apa yang kita lakukan di sini adalah kucing
(paparan) fail ujian kami, dan menghuraikannya dengan ungkapan biasa yang dilanjutkan (terima kasih kepada -E
pilihan) menggunakan sed. Kita boleh menulis ungkapan biasa ini menggunakan ungkapan biasa yang tidak dilanjutkan (dalam SED) seperti berikut;
$ CAT TEST1 | sed's | \ ([a-o] \+\).*\ ([A-z] \+\) | \ 2 \ 1 | ' G ABCDEFGHIJKLMNO 0123456789
Yang sama persis, kecuali kami menambah a \
watak sebelum masing -masing (
, )
dan +
watak, menunjukkan kepada SED kita mahu mereka dihuraikan sebagai kod ekspresi biasa, dan bukan sebagai aksara biasa. Mari kita lihat ungkapan biasa itu sendiri.
Mari kita gunakan format ekspresi biasa yang dilanjutkan untuk ini, kerana lebih mudah untuk menghuraikan secara visual.
s | ([a-o]+).*([A-z]+) | \ 2 \ 1 |
Di sini kita menggunakan perintah pengganti sed (s
pada permulaan arahan), diikuti dengan carian (pertama | ... |
bahagian) dan ganti (kedua | ... |
bahagian) bahagian.
Di bahagian carian, kami mempunyai dua kumpulan pemilihan, masing -masing dikelilingi dan dibatasi oleh (
dan )
, iaitu ([a-o]+)
dan ([A-z]+)
. Kumpulan pemilihan ini, mengikut urutan yang diberikan, akan dicari semasa mencari rentetan. Perhatikan bahawa di antara kumpulan pemilihan, kami mempunyai .*
ungkapan biasa, yang pada dasarnya bermaksud Mana -mana watak, 0 atau lebih kali. Ini akan sesuai dengan ruang kami di antara abcdefghijklmnopqrstuvwxyz
dan A B C D E F G
dalam fail input, dan berpotensi lebih.
Dalam kumpulan carian pertama kami, kami mencari sekurang -kurangnya satu kejadian A-O
diikuti oleh sebarang kejadian lain A-O
, ditunjukkan oleh +
kualifikasi. Dalam kumpulan carian kedua, kami mencari huruf besar antara A
dan Z
, Dan ini sekali lagi satu atau lebih kali dalam urutan.
Akhirnya, di bahagian ganti kami sed
perintah ungkapan biasa, kita akan Panggil Kembali/Ingat Teks yang dipilih oleh kumpulan carian ini, dan masukkannya sebagai rentetan pengganti. Perhatikan bahawa pesanan sedang dibalikkan; output pertama teks yang dipadankan oleh kumpulan pemilihan kedua (melalui penggunaan \ 2
menunjukkan kumpulan pemilihan kedua), maka teks yang dipadankan oleh kumpulan pemilihan pertama (\ 1
).
Walaupun ini mungkin mudah, hasilnya di tangan (G ABCDEFGHIJKLMNO 0123456789
) mungkin tidak jelas. Bagaimana kita longgar A B C D E F
sebagai contoh? Kami juga hilang pqrstuvwxyz
- Adakah anda perasan?
Apa yang berlaku ialah ini; Kumpulan pemilihan pertama kami menangkap teks abcdefghijklmno
. Kemudian, diberi .*
(Mana -mana watak, 0 atau lebih kali) semua watak dipadankan - dan ini penting; hingga tahap maksimum - sehingga kita dapati ekspresi biasa yang sesuai yang akan berlaku, jika ada. Kemudian, akhirnya, kami sepadan dengan surat keluar dari A-Z
julat, dan ini lebih banyak kali.
Adakah anda mula melihat mengapa kami hilang A B C D E F
dan pqrstuvwxyz
? Walaupun ia tidak jelas, .*
menyimpan watak yang sepadan sehingga terakhir A-Z
dipadankan, yang akan berlaku G
di dalam A B C D E F G
tali.
Walaupun kami menentukan satu atau lebih (Melalui penggunaan +
) watak -watak yang akan dipadankan, ungkapan biasa ini telah ditafsirkan dengan betul oleh sed dari kiri ke kanan, dan sed hanya berhenti dengan padanan mana -mana watak (.*
) apabila ia tidak lagi dapat memenuhi premis yang akan ada sekurang-kurangnya satu huruf besar A-Z
watak akan datang.
Dalam jumlah, pqrstuvwxyz abcdef
digantikan oleh .*
Daripada hanya ruang yang akan membaca ekspresi biasa ini secara semula jadi, tetapi tidak betul, membaca. Dan, kerana kita tidak menangkap apa sahaja yang dipilih oleh .*
, Pemilihan ini hanya jatuh dari output.
Perhatikan juga bahawa mana -mana bahagian yang tidak dipadankan oleh bahagian carian hanya disalin ke output: sed
hanya akan bertindak pada apa jua ungkapan biasa (atau padanan teks) yang dijumpai.
Contoh 3: Memilih semua yang tidak
Contoh sebelumnya juga membawa kami ke kaedah lain yang menarik, yang mungkin anda akan menggunakan sedikit yang adil jika anda menulis ungkapan biasa secara teratur, dan itu memilih teks dengan cara yang sepadan Semua itu tidak. Terdengar seperti perkara yang menyeronokkan untuk dikatakan, tetapi tidak jelas apa maksudnya? Mari lihat contoh:
$ CAT TEST1 ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFG 0123456789 $ CAT TEST1 | sed -E 's | [^]*| _ |' _ ABCDEFG 0123456789
Ungkapan biasa yang mudah, tetapi yang sangat kuat. Di sini, bukannya menggunakan .*
dalam beberapa bentuk atau fesyen yang telah kami gunakan [^]*
. Bukannya mengatakan (oleh .*
) sepadan dengan mana -mana watak, 0 atau lebih kali, Kami sekarang menyatakan Padankan watak bukan ruang, 0 atau lebih kali.
Walaupun ini kelihatan agak mudah, anda akan menyedari kekuatan menulis ungkapan biasa dengan cara ini. Fikirkan semula sebagai contoh mengenai contoh terakhir kami, di mana kami tiba -tiba mempunyai sebahagian besar teks yang dipadankan dengan cara yang agak tidak dijangka. Ini dapat dielakkan dengan sedikit mengubah ungkapan biasa kami dari contoh sebelumnya, seperti berikut:
$ CAT TEST1 | sed -E 's | ([a-o]+) [^a]+([a-z]+) | \ 2 \ 1 |' Abcdefg abcdefghijklmno 0123456789
Tidak sempurna, tetapi sudah lebih baik; Sekurang -kurangnya kita dapat memelihara A B C D E F
bahagian. Yang kami buat hanyalah perubahan .*
ke [^A]+
. Dengan kata lain, terus mencari watak, sekurang -kurangnya satu, kecuali A
. Sekali A
didapati bahawa sebahagian daripada ungkapan parsing biasa berhenti. A
sendiri juga tidak akan dimasukkan dalam perlawanan.
Contoh 4: Kembali ke keperluan asal kami
Bolehkah kita melakukan yang lebih baik dan memang menukar lajur pertama dan kedua dengan betul?
Ya, tetapi tidak dengan mengekalkan ungkapan biasa sebagai-is-is. Lagipun, ia melakukan apa yang kami minta lakukan; Padankan semua watak dari A-O
menggunakan kumpulan carian pertama (dan output kemudian pada akhir rentetan), dan kemudian buang Mana -mana watak sehingga sed sampai A
. Kami boleh membuat resolusi akhir isu ini - ingat kami hanya mahu ruang dipadankan - dengan memperluaskan/menukar a-o
ke A-Z
, atau dengan hanya menambahkan kumpulan carian lain, dan memadankan ruang secara harfiah:
$ CAT TEST1 | sed -E 's | ([a-o]+) ([^]+) [] ([a-z]+) | \ 3 \ 1 \ 2 |' ABCDEFG ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789
Hebat! Tetapi ungkapan biasa kelihatan terlalu kompleks sekarang. Kami sepadan a-o
satu atau lebih kali dalam kumpulan pertama, maka mana-mana watak bukan ruang (sehingga sed mencari ruang atau akhir rentetan) dalam kumpulan kedua, maka ruang literal dan akhirnya A-Z
satu atau lebih kali.
Bolehkah kita mempermudahkannya? Ya. Dan ini harus menyerlahkan bagaimana seseorang dapat dengan mudah melampaui skrip ekspresi biasa.
$ CAT TEST1 | sed -E 's | ([^]+) ([^]+) | \ 2 \ 1 |' ABCDEFG ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789 $ CAT TEST1 | awk 'print $ 2 "" $ 1 "" $ 3' abcdefg abcdefghijklmnopqrstuvwxyz 0123456789
Kedua -dua penyelesaian mencapai keperluan asal, menggunakan alat yang berbeza, regex yang banyak dipermudahkan untuk perintah sed, dan tanpa bug, sekurang -kurangnya untuk rentetan input yang disediakan. Bolehkah ini mudah salah?
$ CAT TEST1 ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFG 0123456789 $ CAT TEST1 | sed -E 's | ([^]+) ([^]+) | \ 2 \ 1 |' ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789 ABCDEFG
Ya. Apa yang kami lakukan ialah menambah ruang tambahan dalam input, dan menggunakan ungkapan biasa yang sama output kami kini benar -benar salah; Lajur kedua dan ketiga telah ditukar dan bukannya tinju dua. Sekali lagi keperluan untuk menguji ekspresi biasa mendalam dan dengan input yang berbeza-beza diserlahkan. Perbezaan output adalah semata-mata kerana corak ruang ruang tanpa ruang ruang hanya boleh dipadankan oleh bahagian terakhir rentetan input kerana ruang berganda.
Contoh 5: LS Gotcha?
Kadang -kadang, tetapan tahap sistem operasi, seperti contohnya menggunakan output warna untuk penyenaraian direktori atau tidak (yang boleh ditetapkan secara lalai!), akan menyebabkan skrip baris perintah berkelakuan tidak menentu. Walaupun bukan kesalahan langsung ekspresi biasa dengan apa cara sekalipun, ia adalah gotcha yang boleh berjalan dengan lebih mudah apabila menggunakan ungkapan biasa. Mari lihat contoh:
output warna LS mencatatkan hasil arahan yang mengandungi ungkapan biasa$ ls -d t* test1 test2 $ ls -d t* 2 | sed's | 2 | 1 | ' test1 $ ls -d t*2 | sed's | 2 | 1 | ' | Xargs LS LS: Tidak dapat mengakses "
Dalam contoh ini, kami mempunyai direktori (test2) dan fail (test1), kedua -duanya disenaraikan oleh yang asal ls -d
perintah. Kemudian kami mencari semua fail dengan corak nama fail t*2
, dan keluarkan 2 dari nama fail menggunakan sed
. Hasilnya adalah teks ujian
. Nampaknya kita boleh menggunakan output ini ujian
segera untuk arahan lain, dan kami menghantarnya melalui Xargs
kepada ls
perintah, mengharapkan ls
Perintah untuk menyenaraikan fail ujian1
.
Walau bagaimanapun, ini tidak berlaku, dan sebaliknya kita mendapat output yang sangat kompleks-ke-manusia. Sebabnya mudah: direktori asal disenaraikan dalam warna biru gelap, dan warna ini, ditakrifkan sebagai satu siri kod warna. Apabila anda melihatnya buat kali pertama, output sukar difahami. Walau bagaimanapun, penyelesaiannya mudah;
$ ls -d -color = never t*2 | sed's | 2 | 1 | ' | XARGS LS TEST1
Kami membuat ls
output arahan penyenaraian tanpa menggunakan warna. Ini benar -benar membetulkan masalah di tangan, dan menunjukkan kepada kita bagaimana kita dapat menyimpan di belakang fikiran kita keperluan untuk mengelakkan tetapan & gotchas tertentu, tetapi signifikan, yang boleh memecahkan kerja ekspresi biasa kita apabila dilaksanakan dalam persekitaran yang berbeza, perkakasan yang berbeza, atau sistem pengendalian yang berbeza.
Bersedia untuk meneroka lebih jauh sendiri? Mari kita lihat beberapa ungkapan biasa yang lebih biasa yang terdapat di Bash:
Ungkapan | Penerangan |
---|---|
. | Apa -apa watak, kecuali Newline |
[A-C] | Satu watak julat yang dipilih, dalam kes ini A, B, C |
[A-Z] | Satu watak julat yang dipilih, dalam kes ini a-z |
[0-9AF-Z] | Satu watak julat yang dipilih, dalam kes ini 0-9, A, dan F-Z |
[^A-za-z] | Satu watak di luar julat yang dipilih, dalam kes ini misalnya '1' akan memenuhi syarat |
\ * atau * | Sebilangan pertandingan (0 atau lebih). Gunakan * semasa menggunakan ungkapan biasa di mana ungkapan lanjutan tidak didayakan (lihat contoh pertama di atas) |
\+ atau + | 1 atau lebih perlawanan. Idem komen sebagai * |
\ (\) | Kumpulan menangkap. Kali pertama ini digunakan, nombor kumpulan adalah 1, dll. |
^ | Permulaan rentetan |
$ | Akhir rentetan |
\ d | Satu digit |
\ D | Satu bukan digit |
\ s | Satu ruang putih |
\ S | Satu ruang bukan putih |
a | d | Satu watak daripada kedua -dua (alternatif untuk menggunakan []), 'a' atau 'd' |
\ | Melarikan diri dari watak khas, atau menunjukkan kami ingin menggunakan ungkapan biasa di mana ekspresi lanjutan tidak didayakan (lihat contoh pertama di atas) |
\ b | Watak Backspace |
\ n | Watak baru |
\ r | Watak pulangan kereta |
\ t | Watak tab |
Kesimpulan
Dalam tutorial ini, kami melihat mendalam di Bash Expression Regular. Kami mendapati keperluan untuk menguji ekspresi biasa kami dengan panjang lebar, dengan input yang berbeza -beza. Kami juga melihat bagaimana perbezaan OS kecil, seperti menggunakan warna untuk ls
arahan atau tidak, boleh menyebabkan hasil yang sangat tidak dijangka. Kami mempelajari keperluan untuk mengelakkan penampan carian ekspresi biasa yang terlalu generik, dan cara menggunakan ekspresi biasa yang dilanjutkan.
Nikmati Menulis Ekspresi Biasa Lanjutan, dan tinggalkan kami komen di bawah dengan contoh yang paling keren anda!
Tutorial Linux Berkaitan:
- Bash regexps untuk pemula dengan contoh
- Ungkapan biasa python dengan contoh
- Manipulasi data besar untuk keseronokan dan keuntungan bahagian 3
- Pengenalan kepada Automasi, Alat dan Teknik Linux
- Perkara yang hendak dipasang di Ubuntu 20.04
- Manipulasi data besar untuk keseronokan dan keuntungan bahagian 2
- Manipulasi data besar untuk keseronokan dan keuntungan bahagian 1
- Menguasai Gelung Skrip Bash
- Mint 20: Lebih baik daripada Ubuntu dan Microsoft Windows?
- Perkara yang perlu dilakukan setelah memasang ubuntu 20.04 Focal Fossa Linux