Lanjutan regex bash canggih dengan contoh

Lanjutan regex bash canggih dengan contoh

Menggunakan kekuatan ekspresi reguler, seseorang dapat menguraikan dan mengubah dokumen dan string berbasis tekstual. Artikel ini untuk pengguna tingkat lanjut, yang sudah terbiasa dengan ekspresi reguler dasar di Bash. Untuk Pengantar Ekspresi Reguler Bash, lihat Ekspresi Reguler Bash kami untuk Pemula dengan Contoh Artikel. Artikel lain yang mungkin Anda temukan menarik adalah ekspresi reguler di Python.

Siap Memulai? Menyelam dan belajar menggunakan regexps seperti pro!

Dalam tutorial ini Anda akan belajar:

  • Bagaimana menghindari perbedaan sistem operasi kecil dari mempengaruhi ekspresi reguler Anda
  • Cara menghindari penggunaan pola pencarian ekspresi reguler yang terlalu generik seperti .*
  • Bagaimana cara mempekerjakan, atau tidak mempekerjakan, memperluas sintaks ekspresi reguler
  • Contoh Penggunaan Lanjutan dari Ekspresi Reguler Kompleks dalam Bash
Lanjutan regex bash canggih dengan contoh

Persyaratan dan konvensi perangkat lunak yang digunakan

Persyaratan Perangkat Lunak dan Konvensi Baris Perintah Linux
Kategori Persyaratan, konvensi atau versi perangkat lunak yang digunakan
Sistem Distribusi Linux-independen
Perangkat lunak Baris perintah bash, sistem berbasis Linux
Lainnya Utilitas SED digunakan sebagai contoh alat untuk menggunakan ekspresi reguler
Konvensi # - mensyaratkan Linux -Commands untuk dieksekusi dengan hak istimewa root baik secara langsung sebagai pengguna root atau dengan menggunakan sudo memerintah
$-mensyaratkan Linux-Commands untuk dieksekusi sebagai pengguna reguler yang tidak istimewa

Contoh 1: Kepala menggunakan ekspresi reguler yang diperluas

Untuk tutorial ini, kami akan menggunakan SED sebagai mesin pemrosesan ekspresi reguler utama kami. Setiap contoh yang diberikan biasanya dapat diangkut langsung ke mesin lain, seperti mesin ekspresi reguler yang termasuk dalam GREP, AWK dll.

Satu hal yang selalu perlu diingat ketika bekerja dengan ekspresi reguler, adalah bahwa beberapa mesin regex (seperti yang ada di SED) mendukung sintaks ekspresi reguler reguler dan diperpanjang. Misalnya, SED akan memungkinkan Anda untuk menggunakan -E Opsi (opsi steno untuk --Regexp-Extended), memungkinkan Anda menggunakan ekspresi reguler yang diperluas dalam skrip SED.

Secara praktis, ini menghasilkan perbedaan kecil dalam idiom sintaks ekspresi reguler saat menulis skrip ekspresi reguler. Mari kita 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 memenuhi syarat kisaran A-C (diganti secara global G kualifikasi) sesuai kebutuhan satu atau lebih kejadian. Perhatikan bahwa sintaks, khususnya \+. Namun, saat kami mengubah ini \+ ke +, Perintah tersebut menghasilkan output yang sama sekali berbeda. Ini karena + tidak ditafsirkan sebagai karakter standar plus, dan bukan sebagai perintah regex.

Ini kemudian dibuktikan dengan komando ketiga di mana literal +, serta e sebelum itu, ditangkap oleh ekspresi reguler [a-e]+, dan berubah menjadi _.

Melihat ke belakang itu perintah pertama, kita sekarang dapat melihat bagaimana \+ ditafsirkan sebagai ekspresi reguler non-literal +, untuk diproses oleh sed.

Akhirnya, dalam perintah terakhir kami memberi tahu SED bahwa kami secara khusus ingin menggunakan sintaks yang diperluas dengan menggunakan -E opsi sintaks yang diperpanjang untuk sed. Perhatikan bahwa istilah tersebut diperpanjang memberi kita petunjuk tentang apa yang terjadi di latar belakang; Sintaks ekspresi reguler adalah diperluas untuk mengaktifkan berbagai perintah regex, seperti dalam kasus ini +.

Sekali -E digunakan, meskipun kami masih menggunakan + dan tidak \+, sedlah dengan benar menafsirkan + sebagai instruksi ekspresi reguler.

Saat Anda menulis banyak ekspresi reguler, perbedaan kecil dalam mengekspresikan pikiran Anda ke dalam ekspresi reguler memudar ke latar belakang, dan Anda akan cenderung mengingat yang paling penting.

Ini juga menyoroti perlunya selalu menguji ekspresi reguler secara luas, mengingat berbagai kemungkinan input, bahkan yang tidak Anda harapkan.

Contoh 2: Modifikasi String Tugas Berat

Untuk contoh ini, dan yang berikutnya, kami telah menyiapkan file tekstual. Jika Anda ingin berlatih bersama, Anda dapat menggunakan perintah berikut untuk membuat file ini sendiri:

$ echo 'abcdefghijklmnopqrstuvwxyz abcdefg 0123456789'> test1 $ cat test1 abcdefghijklmnopqrstuvwxyz abcdefg 0123456789 

Sekarang mari kita lihat contoh modifikasi string pertama kami: kami ingin kolom kedua (ABCDEFG) datang sebelum yang pertama (ABCDEFGHIJKLMNOPQRSTUVWXYZ).

Sebagai permulaan, kami melakukan upaya fiksi ini:

$ cat test1 abcdefghijklmnopqrstuvwxyz abcdefg 0123456789 $ cat test1 | sed -e | ([a -o]+).*([A-z]+) | \ 2 \ 1 | ' G ABCDEFGHIJKLMNO 0123456789 

Apakah Anda memahami ekspresi reguler ini? Jika demikian, Anda sudah menjadi penulis ekspresi reguler yang sangat canggih, dan Anda dapat memilih untuk melompat ke depan ke contoh -contoh berikut, membaca sekilas mereka untuk melihat apakah Anda dapat dengan cepat memahaminya, atau membutuhkan sedikit bantuan.

Apa yang kami lakukan di sini adalah kucing (Tampilkan) File Test1 kami, dan piratkan dengan ekspresi reguler yang diperpanjang (terima kasih kepada -E opsi) menggunakan sed. Kami bisa menulis ekspresi reguler ini menggunakan ekspresi reguler yang tidak diperpanjang (di SED) sebagai berikut;

$ Cat test1 | sed 's | \ ([a-o] \+\).*\ ([A-z] \+\) | \ 2 \ 1 | ' G ABCDEFGHIJKLMNO 0123456789 

Yang persis sama, kecuali kami menambahkan a \ karakter sebelum masing -masing (, ) Dan + karakter, menunjukkan kepada sed kami ingin mereka diuraikan sebagai kode ekspresi reguler, dan bukan karakter normal. Sekarang mari kita lihat ekspresi reguler itu sendiri.

Mari kita gunakan format ekspresi reguler yang diperluas untuk ini, karena lebih mudah diurai secara visual.

s | ([a-o]+).*([A-z]+) | \ 2 \ 1 | 

Di sini kami menggunakan perintah Sed Sopitute (S Di awal perintah), diikuti dengan pencarian (pertama |… | sebagian) dan ganti (kedua |… | bagian) bagian.

Di bagian pencarian, kami memiliki dua grup seleksi, Masing -masing dikelilingi dan dibatasi oleh ( Dan ), yaitu ([a-o]+) Dan ([A-z]+). Grup seleksi ini, dalam urutan yang diberikan, akan dicari saat mencari string. Perhatikan bahwa di antara grup seleksi, kami memiliki a .* ekspresi reguler, yang pada dasarnya berarti Karakter apa pun, 0 atau lebih kali. Ini akan cocok dengan ruang kami di antaranya ABCDEFGHIJKLMNOPQRSTUVWXYZ Dan ABCDEFG di file input, dan berpotensi lebih.

Di grup pencarian pertama kami, kami mencari setidaknya satu kemunculan a-o diikuti oleh sejumlah kejadian lainnya a-o, ditunjukkan oleh + Kualifikasi. Di grup pencarian kedua, kami mencari huruf besar di antara A Dan Z, Dan ini lagi satu atau lebih kali secara berurutan.

Akhirnya, di bagian ganti kami dari sed Perintah ekspresi reguler, kami akan Hubungi Kembali/Ingat Teks yang dipilih oleh grup pencarian ini, dan masukkan sebagai string pengganti. Perhatikan bahwa pesanan sedang dibalik; output pertama teks yang cocok dengan grup seleksi kedua (melalui penggunaan \ 2 menunjukkan grup seleksi kedua), kemudian teks yang cocok dengan grup seleksi pertama (\ 1).

Meskipun ini mungkin terdengar mudah, hasilnya (G ABCDEFGHIJKLMNO 0123456789) mungkin tidak segera jelas. Bagaimana kami longgar Abcdef Misalnya? Kami juga kalah PQRSTUVWXYZ - Apakah kamu menyadari?



Apa yang terjadi adalah ini; Grup pilihan pertama kami menangkap teks ABCDEFGHIJKLMNO. Kemudian, mengingat .* (Karakter apa pun, 0 atau lebih kali) semua karakter dicocokkan - dan ini penting; Sejauh maksimum - sampai kami menemukan ekspresi reguler yang cocok dengan yang berlaku berikutnya, jika ada. Kemudian, akhirnya, kami mencocokkan surat apa pun dari A-z jangkauan, dan ini lagi kali.

Apakah Anda mulai melihat mengapa kami kalah Abcdef Dan PQRSTUVWXYZ? Meskipun sama sekali tidak jelas, itu .* tetap mencocokkan karakter sampai terakhir A-z dicocokkan, yang akan terjadi G dalam ABCDEFG rangkaian.

Meskipun kami menentukan satu atau lebih (melalui penggunaan +) Karakter yang harus dicocokkan, ekspresi reguler khusus ini ditafsirkan dengan benar oleh SED dari kiri ke kanan, dan SED hanya berhenti dengan pencocokan karakter apa pun (.*) ketika itu tidak bisa lagi memenuhi premis yang akan ada setidaknya satu huruf besar A-z karakter mendatang.

Secara keseluruhan, PQRSTUVWXYZ ABCDEF digantikan oleh .* Alih -alih hanya ruang seperti orang akan membaca ekspresi reguler ini dalam membaca yang lebih alami, tetapi tidak benar,. Dan, karena kami tidak menangkap apa pun yang dipilih oleh .*, Pilihan ini hanya dijatuhkan dari output.

Perhatikan juga bahwa setiap bagian yang tidak cocok dengan bagian pencarian hanya disalin ke output: sed hanya akan bertindak berdasarkan apa pun yang ditemukan oleh ekspresi reguler (atau kecocokan teks).

Contoh 3: Memilih semua yang tidak

Contoh sebelumnya juga membawa kami ke metode lain yang menarik, yang kemungkinan besar Anda akan menggunakan bit yang adil jika Anda menulis ekspresi reguler secara teratur, dan itu memilih teks dengan cara mencocokkan Semua itu tidak. Kedengarannya hal yang menyenangkan untuk dikatakan, tetapi tidak jelas apa artinya? Mari kita lihat contoh:

$ cat test1 abcdefghijklmnopqrstuvwxyz abcdefg 0123456789 $ cat test1 | sed -e | [^]*| _ | ' _ ABCDEFG 0123456789 

Ekspresi reguler yang sederhana, tetapi yang sangat kuat. Di sini, alih -alih menggunakan .* Dalam beberapa bentuk atau mode yang telah kami gunakan [^]*. Alih -alih mengatakan (oleh .*) Cocokkan karakter apa pun, 0 atau lebih kali, Kami sekarang menyatakan Cocokkan karakter non-ruang, 0 atau lebih kali.

Sementara ini terlihat relatif mudah, Anda akan segera menyadari kekuatan menulis ekspresi reguler dengan cara ini. Pikirkan kembali misalnya tentang contoh terakhir kita, di mana kita tiba -tiba memiliki sebagian besar teks yang cocok dengan cara yang agak tidak terduga. Ini dapat dihindari dengan sedikit mengubah ekspresi reguler kami dari contoh sebelumnya, sebagai berikut:

$ Cat test1 | Sed -e 'S | ([a-o]+) [^a]+([a-z]+) | \ 2 \ 1 |' ABCDEFG ABCDEFGHIJKLMNO 0123456789 

Belum sempurna, tapi sudah lebih baik; setidaknya kami bisa melestarikan Abcdef bagian. Yang kami lakukan hanyalah perubahan .* ke [^A]+. Dengan kata lain, terus cari karakter, setidaknya satu, kecuali A. Sekali A ditemukan bahwa bagian dari penguraian ekspresi reguler berhenti. A sendiri juga tidak akan dimasukkan dalam pertandingan.

Contoh 4: Kembali ke persyaratan asli kami

Dapatkah kita melakukan yang lebih baik dan memang menukar kolom pertama dan kedua dengan benar?

Ya, tapi tidak dengan menjaga ekspresi reguler apa adanya. Lagi pula, itu melakukan apa yang kami minta untuk dilakukan; Cocokkan semua karakter dari a-o menggunakan grup pencarian pertama (dan output nanti di akhir string), dan kemudian membuang Karakter apa pun sampai Sed mencapai A. Kita bisa membuat resolusi akhir dari masalah ini - ingat kita hanya ingin ruang untuk dicocokkan - dengan memperluas/mengubah a-o ke a-z, Atau hanya dengan menambahkan grup pencarian lain, dan mencocokkan ruang secara harfiah:

$ Cat test1 | Sed -e 's | ([a-o]+) ([^]+) [] ([a-z]+) | \ 3 \ 1 \ 2 |' ABCDEFG ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789 

Besar! Tapi ekspresi reguler terlihat terlalu rumit sekarang. Kami cocok a-o satu atau lebih kali dalam kelompok pertama, maka karakter non-ruang apa pun (sampai SED menemukan ruang atau ujung string) pada kelompok kedua, kemudian ruang literal dan akhirnya A-z satu kali atau lebih.

Bisakah kita menyederhanakannya? Ya. Dan ini harus menyoroti bagaimana seseorang dapat dengan mudah terlalu rumit skrip ekspresi reguler.

$ Cat test1 | Sed -e 'S | ([^]+) ([^]+) | \ 2 \ 1 |' ABCDEFG ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789 $ CAT TEST1 | awk 'print $ 2 "" $ 1 "" $ 3' abcdefg abcdefghijklmnopqrstuvwxyz 0123456789 


Kedua solusi mencapai persyaratan asli, menggunakan alat yang berbeda, regex yang sangat disederhanakan untuk perintah SED, dan tanpa bug, setidaknya untuk string input yang disediakan. Bisakah ini dengan mudah salah?

$ cat test1 abcdefghijklmnopqrstuvwxyz abcdefg 0123456789 $ cat test1 | Sed -e 'S | ([^]+) ([^]+) | \ 2 \ 1 |' ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789 ABCDEFG 

Ya. Yang kami lakukan hanyalah menambahkan ruang tambahan dalam input, dan menggunakan ekspresi reguler yang sama output kami sekarang benar -benar salah; kolom kedua dan ketiga ditukar, bukan tinju dua. Sekali lagi kebutuhan untuk menguji ekspresi reguler secara mendalam dan dengan beragam input disorot. Perbedaan output adalah hanya karena ruang tanpa-ruang tidak spasi hanya dapat dicocokkan dengan bagian terakhir dari string input karena ruang ganda.

Contoh 5: ls gotcha?

Terkadang, pengaturan level sistem operasi, seperti misalnya menggunakan output warna untuk daftar direktori atau tidak (yang dapat diatur secara default!), akan menyebabkan skrip baris perintah berperilaku tidak menentu. Meskipun bukan kesalahan langsung dari ekspresi reguler dengan cara apa pun, itu adalah gotcha yang dapat ditabrak lebih mudah saat menggunakan ekspresi reguler. Mari kita lihat contoh:

output warna ls noda hasil perintah yang berisi ekspresi reguler
$ 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 memiliki direktori (test2) dan file (test1), keduanya terdaftar oleh aslinya LS -D memerintah. Kemudian kami mencari semua file dengan pola nama file t*2, dan hapus 2 dari nama file menggunakan sed. Hasilnya adalah teksnya tes. Sepertinya kita bisa menggunakan output ini tes segera untuk perintah lain, dan kami mengirimkannya melalui xargs ke ls perintah, mengharapkan ls Perintah untuk mendaftar file test1.

Namun, ini tidak terjadi, dan sebaliknya kami mendapatkan kembali output yang sangat kompleks. Alasannya sederhana: Direktori asli terdaftar dalam warna biru gelap, dan warna ini, didefinisikan sebagai serangkaian kode warna. Saat Anda melihat ini untuk pertama kalinya, output sulit dipahami. Namun solusinya sederhana;

$ ls -d - -color = tidak pernah t*2 | Sed 'S | 2 | 1 |' | xargs ls test1 

Kami membuat ls perintah output daftar tanpa menggunakan warna apa pun. Ini benar -benar memperbaiki masalah yang ada, dan menunjukkan kepada kita bagaimana kita dapat menjaga di benak kita, kebutuhan untuk menghindari pengaturan & gotcha spesifik yang kecil, tetapi signifikan, yang dapat mematahkan pekerjaan ekspresi reguler kita ketika dieksekusi di lingkungan yang berbeda, di berbagai, ON perangkat keras yang berbeda, atau pada sistem operasi yang berbeda.

Siap menjelajahi lebih lanjut sendiri? Mari kita lihat beberapa ekspresi reguler yang lebih umum tersedia di Bash:

Ekspresi Keterangan
. Karakter apa pun, kecuali newline
[A-C] Salah satu karakter dari rentang yang dipilih, dalam hal ini A, B, C
[A-z] Salah satu karakter dari kisaran yang dipilih, dalam hal ini A-Z
[0-9AF-Z] Salah satu karakter dari rentang yang dipilih, dalam hal ini 0-9, A, dan F-Z
[^A-za-z] Satu karakter di luar kisaran yang dipilih, dalam hal ini misalnya '1' akan memenuhi syarat
\* atau * Sejumlah kecocokan (0 atau lebih). Gunakan * Saat menggunakan ekspresi reguler di mana ekspresi yang diperluas tidak diaktifkan (lihat contoh pertama di atas)
\+ atau + 1 pertandingan atau lebih. Komentar idem sebagai *
\ (\) Grup penangkapan. Pertama kali ini digunakan, nomor grup adalah 1, dll.
^ Mulai dari string
$ Akhir string
\D Satu digit
\D Satu non-digit
\S Satu ruang putih
\S Satu ruang non-putih
a | d Satu karakter dari keduanya (alternatif untuk menggunakan []), 'a' atau 'd'
\ Lolos dari karakter khusus, atau menunjukkan kami ingin menggunakan ekspresi reguler di mana ekspresi yang diperluas tidak diaktifkan (lihat contoh pertama di atas)
\B Karakter Backspace
\N Karakter garis baru
\R Karakter pengembalian kereta
\T Karakter Tab

Kesimpulan

Dalam tutorial ini, kami melihat mendalam di Ekspresi Reguler Bash. Kami menemukan kebutuhan untuk menguji ekspresi reguler kami secara panjang lebar, dengan input yang bervariasi. Kami juga melihat betapa kecilnya perbedaan OS, seperti menggunakan warna ls Perintah atau tidak, dapat menyebabkan hasil yang sangat tidak terduga. Kami belajar kebutuhan untuk menghindari pola pencarian ekspresi reguler yang terlalu generik, dan cara menggunakan ekspresi reguler yang diperluas.

Nikmati menulis ekspresi reguler lanjutan, dan tinggalkan kami komentar di bawah ini dengan contoh paling keren Anda!

Tutorial Linux Terkait:

  • Bash Regexps untuk pemula dengan contoh
  • Ekspresi reguler Python dengan contoh
  • Manipulasi data besar untuk kesenangan dan keuntungan bagian 3
  • Pengantar Otomatisasi Linux, Alat dan Teknik
  • Hal -hal yang harus diinstal pada ubuntu 20.04
  • Manipulasi data besar untuk kesenangan dan keuntungan bagian 2
  • Manipulasi data besar untuk kesenangan dan keuntungan bagian 1
  • Menguasai loop skrip bash
  • Mint 20: Lebih baik dari Ubuntu dan Microsoft Windows?
  • Hal -hal yang harus dilakukan setelah menginstal ubuntu 20.04 FOSSA FOSSA Linux