GNU/Linux >> Belajar Linux >  >> Linux

Regex dan grep:Aliran data dan blok penyusun

Dalam Memperkenalkan ekspresi reguler , saya membahas apa itu dan mengapa mereka berguna. Sekarang mari kita lihat lebih dalam bagaimana mereka dibuat. Karena GNU grep adalah salah satu alat yang paling sering saya gunakan (yang menyediakan implementasi ekspresi reguler yang kurang lebih standar), saya akan menggunakan kumpulan ekspresi itu sebagai dasar untuk artikel ini. Kami kemudian akan melihat sed (alat lain yang menggunakan ekspresi reguler) di artikel selanjutnya.

Semua implementasi ekspresi reguler berbasis baris. Pola yang dibuat oleh kombinasi satu atau lebih ekspresi dibandingkan dengan setiap baris aliran data. Saat kecocokan dibuat, tindakan dilakukan pada garis itu seperti yang ditentukan oleh alat yang digunakan.

Misalnya, ketika kecocokan pola terjadi dengan grep , tindakan yang biasa dilakukan adalah meneruskan garis itu ke STDOUT dan membuang garis yang tidak cocok dengan polanya. Seperti yang kita lihat di Memulai ekspresi reguler:Contoh , -v opsi membalikkan tindakan tersebut, sehingga baris dengan kecocokan akan dibuang.

Setiap baris aliran data dievaluasi sendiri. Pikirkan setiap baris aliran data sebagai catatan, di mana alat yang menggunakan regex memproses satu catatan pada satu waktu. Saat kecocokan dibuat, tindakan yang ditentukan oleh alat yang digunakan diambil pada baris yang berisi string yang cocok.

Blok penyusun Regex

Tabel berikut berisi daftar ekspresi blok penyusun dasar dan karakter meta yang diimplementasikan oleh grep GNU perintah (dan sebagian besar implementasi regex lainnya), dan deskripsinya. Saat digunakan dalam suatu pola, masing-masing ekspresi atau metakarakter ini cocok dengan satu karakter dalam aliran data yang diurai:

Ekspresi Deskripsi

Karakter alfanumerik

Literal

A-Z,a-z,0-9

Semua alfanumerik dan beberapa karakter tanda baca dianggap sebagai literal. Jadi huruf a dalam regex akan selalu cocok dengan huruf "a" di aliran data yang diurai. Tidak ada ambiguitas untuk karakter ini. Setiap karakter literal cocok dengan satu dan hanya satu karakter.
. (titik) Metakarakter titik (.) adalah bentuk ekspresi paling dasar. Ini cocok dengan karakter tunggal apa pun di posisi yang ditemuinya dalam sebuah pola. Jadi polanya b.g akan cocok dengan "besar", "lebih besar", "tas", "baguette", dan "rawa", tetapi tidak cocok dengan "anjing", "blog", "pelukan", "lag", "gag", "kaki", dll .

Ekspresi tanda kurung

[daftar karakter]

GNU grep menyebutnya sebagai ekspresi braket, dan ini sama dengan satu set untuk shell Bash. Tanda kurung menyertakan daftar karakter yang cocok untuk lokasi karakter tunggal dalam pola. [abcdABCD] cocok dengan huruf "a," b," "c," atau "d" dalam huruf besar atau kecil. [a-dA-D] menentukan berbagai karakter yang menciptakan kecocokan yang sama. [a-zA-Z] cocok dengan alfabet dalam huruf besar dan kecil.

[:nama kelas:]

Kelas karakter

Ini adalah upaya POSIX pada standarisasi regex. Nama-nama kelas seharusnya jelas. Misalnya, [:alnum:] class cocok dengan semua karakter alfanumerik. Kelas lainnya adalah [:digit :] yang cocok dengan satu digit 0-9, [:alpha:] ,[:space:] , dan seterusnya. Perhatikan bahwa mungkin ada masalah karena perbedaan urutan penyortiran di lokasi yang berbeda. Baca grep halaman manual untuk detailnya.

^ dan $

Jangkar

Kedua metakarakter ini masing-masing cocok dengan awal dan akhir baris. Mereka dikatakan menambatkan sisa pola ke awal atau akhir garis. Ekspresi ^b.g hanya akan cocok dengan "besar", "lebih besar", "tas", dll., seperti yang ditunjukkan di atas jika muncul di awal baris yang diurai. Pola b.g$ akan cocok dengan "besar" atau "kantong" hanya jika muncul di akhir baris, tetapi tidak "lebih besar".

Mari kita jelajahi blok bangunan ini sebelum melanjutkan dengan beberapa pengubah. File teks yang akan kita gunakan untuk Eksperimen 3 berasal dari proyek lab yang saya buat untuk kelas Linux lama yang biasa saya ajar. Awalnya dalam file odt LibreOffice Writer tetapi saya menyimpannya ke file teks ASCII. Sebagian besar pemformatan hal-hal seperti tabel telah dihapus, tetapi hasilnya adalah file teks ASCII panjang yang dapat kita gunakan untuk rangkaian eksperimen ini.

Contoh:entri TOC

Mari kita lihat contoh untuk mengeksplorasi apa yang baru saja kita pelajari. Pertama, buat ~/testing direktori PWD Anda (buat jika Anda belum melakukannya di artikel sebelumnya dalam seri ini), lalu unduh file sampel dari GitHub.

[student@studentvm1 testing]$  wget https://raw.githubusercontent.com/opensourceway/reg-ex-examples/master/Experiment_6-3.txt

Untuk memulai, gunakan less perintah untuk melihat dan menjelajahi Experiment_6-3.txt file selama beberapa menit untuk mendapatkan gambaran tentang isinya.

Sekarang, mari kita gunakan beberapa grep sederhana ekspresi untuk mengekstrak garis dari aliran data input. Daftar Isi (TOC) berisi daftar proyek dan nomor halaman masing-masing dalam dokumen PDF. Mari kita ekstrak TOC yang dimulai dengan garis yang diakhiri dengan dua digit:

[student@studentvm1 testing]$  grep [0-9][0-9]$ Experiment_6-3.txt

Perintah ini sebenarnya bukan yang kita inginkan. Ini menampilkan semua baris yang diakhiri dengan dua digit dan melewatkan entri TOC dengan hanya satu digit. Kita akan melihat bagaimana menangani ekspresi untuk satu atau lebih digit dalam eksperimen selanjutnya. Melihat seluruh file dalam less , kita bisa melakukan sesuatu seperti ini.

[student@studentvm1 testing]$ grep "^Lab Project" Experiment_6-3.txt | grep "[0-9]$"

Perintah ini jauh lebih dekat dengan apa yang kita inginkan, tetapi tidak cukup sampai di sana. Kami mendapatkan beberapa baris dari nanti dalam dokumen yang juga cocok dengan ekspresi ini. Jika Anda mempelajari baris tambahan dan melihat pada dokumen lengkap, Anda dapat melihat mengapa mereka cocok saat tidak menjadi bagian dari TOC.

Perintah ini juga melewatkan entri TOC yang tidak dimulai dengan "Proyek Lab". Terkadang hasil ini adalah yang terbaik yang dapat Anda lakukan, dan memberikan tampilan TOC yang lebih baik daripada sebelumnya. Kita akan melihat bagaimana menggabungkan kedua grep instance menjadi satu dalam eksperimen selanjutnya.

Sekarang, mari kita sedikit memodifikasi perintah ini dan menggunakan ekspresi POSIX. Perhatikan tanda kurung siku ganda ([[]] ) di sekitarnya:

[student@studentvm1 testing]$ grep "^Lab Project" Experiment_6-3.txt | grep "[[:digit:]]$"

Tanda kurung kurawal menghasilkan pesan kesalahan.

Perintah ini memberikan hasil yang sama seperti percobaan sebelumnya.

Contoh:systemd

Mari kita cari sesuatu yang berbeda di file yang sama:

[student@studentvm1 testing]$ grep systemd Experiment_6-3.txt

Perintah ini mencantumkan semua kemunculan "systemd" dalam file. Coba gunakan -i opsi untuk memastikan bahwa Anda mendapatkan semua instance, termasuk yang dimulai dengan huruf besar (bentuk resmi "systemd" semuanya huruf kecil). Atau, Anda dapat mengubah ekspresi literal menjadi Systemd .

Hitung jumlah baris yang berisi string systemd . Saya selalu menggunakan -i untuk memastikan bahwa semua contoh ekspresi pencarian ditemukan terlepas dari kasus:

[student@studentvm1 testing]$ grep -i systemd Experiment_6-3.txt | wc
20      478     3098

Seperti yang Anda lihat, saya memiliki 20 baris, dan Anda harus memiliki nomor yang sama.

Contoh:Metacharacters

Berikut adalah contoh pencocokan metakarakter:tanda kurung siku kiri ([ ). Pertama, mari kita coba tanpa melakukan sesuatu yang istimewa:

[student@studentvm1 testing]$  **grep -i "[" Experiment_6-3.txt**
grep: Invalid regular expression

Kesalahan ini terjadi karena [ diartikan sebagai metakarakter. Kita harus melarikan diri karakter ini dengan garis miring terbalik (\ ) sehingga ditafsirkan sebagai karakter literal dan bukan sebagai karakter meta:

[student@studentvm1 testing]$ grep -i "\[" Experiment_6-3.txt

Kebanyakan metakarakter kehilangan arti khusus mereka ketika digunakan di dalam ekspresi kurung:

  • Untuk memasukkan ] literal , letakkan di urutan pertama dalam daftar.
  • Untuk menyertakan ^ liter literal , letakkan di mana saja kecuali dulu.
  • Untuk memasukkan [ liter literal , letakkan terakhir.

Pengulangan

Ekspresi reguler dapat dimodifikasi menggunakan operator yang memungkinkan Anda menentukan nol, satu, atau lebih pengulangan karakter atau ekspresi. Operator pengulangan ini ditempatkan segera setelah karakter literal atau metakarakter yang digunakan dalam pola:

Operator Deskripsi
?

Dalam regex ? berarti nol atau satu kemunculan paling banyak dari karakter sebelumnya. Jadi misalnya, drives? cocok dengan "drive", dan "drive" tetapi tidak cocok dengan "driver". Hasil ini sedikit berbeda dengan perilaku ? dalam gumpalan.

* Karakter sebelum * akan dicocokkan nol kali atau lebih tanpa batas. Dalam contoh ini, drives* cocok dengan "drive", "drives", dan "drivesss" tetapi tidak cocok dengan "driver". Sekali lagi, ini sedikit berbeda dari perilaku * dalam gumpalan.
+ Karakter sebelum + akan dicocokkan satu kali atau lebih. Karakter harus ada di baris setidaknya sekali agar kecocokan terjadi. Sebagai salah satu contoh, drives+ cocok dengan "drive", dan "drivesss" tetapi tidak cocok dengan "drive" atau "driver".
{n} Operator ini cocok dengan karakter sebelumnya tepat n kali. Ekspresi drives{2} cocok dengan "drivess" tetapi tidak cocok dengan "drive", "drives", "drivesss", atau sejumlah karakter "s" di belakangnya. Namun, karena "drivesssss" berisi string drivess , kecocokan terjadi pada string itu, jadi barisnya akan cocok dengan grep .
{n,} Operator ini cocok dengan karakter sebelumnya sebanyak n kali atau lebih. Ekspresi drives{2,} cocok dengan "drivess" tetapi tidak cocok dengan "drive", "drives", "drivess ," "drives", atau sejumlah karakter "s" di belakangnya. Karena "drivesssss" berisi string drivess , terjadi kecocokan.
{,m} Operator ini cocok dengan karakter sebelumnya tidak lebih dari m kali. Ekspresi drives{,2} cocok dengan "drive", "drives", dan "drivess", tetapi tidak cocok dengan "drivesss", atau sejumlah karakter "s" di belakangnya. Sekali lagi, karena "drivesssss" berisi string drivess , terjadi kecocokan.
{n,m} Operator ini cocok dengan karakter sebelumnya setidaknya n kali, tetapi tidak lebih dari m kali. Ekspresi drives{1,3} cocok dengan "drives", "drivess", dan "drivesss", tetapi tidak cocok dengan "drivessss" atau sejumlah karakter "s" di belakangnya. Sekali lagi, karena "drivesssss" berisi string yang cocok, kecocokan terjadi.

Sebagai contoh, jalankan setiap perintah berikut dan periksa hasilnya dengan cermat, sehingga Anda memahami apa yang terjadi:

[student@studentvm1 testing]$  **grep -E files? Experiment_6-3.txt**
[student@studentvm1 testing]$  **grep -Ei "drives*" Experiment_6-3.txt**
[student@studentvm1 testing]$  **grep -Ei "drives+" Experiment_6-3.txt**
[student@studentvm1 testing]$  **grep -Ei "drives{2}" Experiment_6-3.txt**
[student@studentvm1 testing]$  **grep -Ei "drives{2,}" Experiment_6-3.txt**
[student@studentvm1 testing]$  **grep -Ei "drives{,2}" Experiment_6-3.txt**
[student@studentvm1 testing]$  **grep -Ei "drives{2,3}" Experiment_6-3.txt**

Pastikan untuk bereksperimen dengan pengubah ini pada teks lain dalam file sampel.

Pengubah metakarakter

Masih ada beberapa modifier menarik dan penting yang perlu kita jelajahi:

Pengubah Deskripsi
< Ekspresi khusus ini cocok dengan string kosong di awal kata. Ekspresi <fun akan cocok dengan "kesenangan" dan "Fungsi", tetapi tidak cocok dengan "pengembalian dana".
> Ekspresi khusus ini cocok dengan spasi normal, atau string kosong (" ") di akhir kata, serta tanda baca yang biasanya muncul di string karakter tunggal di akhir kata. Jadi environment> cocok dengan "lingkungan", "lingkungan", dan "lingkungan", tetapi tidak cocok dengan "lingkungan" atau "lingkungan".
^ Dalam ekspresi kelas karakter, operator ini meniadakan daftar karakter. Jadi, sedangkan kelas [a-c] cocok dengan "a", "b", atau "c", di posisi pola tersebut, kelas [^a-c] cocok dengan apa pun kecuali "a," "b," atau "c."
| Bila digunakan dalam regex, | metacharacter adalah operator "atau" logis. Ini secara resmi disebut infix atau alternatif operator. Kami telah menemukan yang ini di Memulai ekspresi reguler:Contoh , di mana kami melihat bahwa regex "Team|^\s*$" artinya, "baris dengan 'Tim' atau (| ) baris kosong yang memiliki nol, satu, atau lebih karakter spasi putih seperti spasi, tab, dan karakter lain yang tidak dapat dicetak."
( and ) Kurung ( and ) memungkinkan kami memastikan urutan perbandingan pola tertentu, seperti yang mungkin digunakan untuk perbandingan logis dalam bahasa pemrograman.

Kami sekarang memiliki cara untuk menentukan batas kata dengan \< dan \> karakter meta. Ini berarti bahwa kita sekarang bisa lebih eksplisit dengan pola kita. Kita juga dapat menggunakan logika dalam pola yang lebih kompleks.

Sebagai contoh, mulailah dengan beberapa pola sederhana. Yang pertama ini memilih semua instance drives tapi bukan drives , drives , atau karakter tambahan "s" tambahan:

 [student@studentvm1 testing]$  **grep -Ei "\<drives\>" Experiment_6-3.txt**

Sekarang mari kita buat pola pencarian untuk menemukan referensi ke tar (perintah arsip tape) dan referensi terkait. Dua iterasi pertama menampilkan lebih dari sekadar tar -baris terkait:

[student@studentvm1 testing]$ grep -Ei "tar" Experiment_6-3.txt
[student@studentvm1 testing]$ grep -Ei "\<tar" Experiment_6-3.txt
[student@studentvm1 testing]$  grep -Ein "\<tar\>" Experiment_6-3.txt

-n opsi pada perintah terakhir di atas menampilkan nomor baris untuk setiap baris tempat terjadi kecocokan. Opsi ini dapat membantu menemukan contoh tertentu dari pola pencarian.

Kiat: Baris data yang cocok dapat melampaui satu layar, terutama saat mencari file besar. Anda dapat menyalurkan aliran data yang dihasilkan melalui utilitas yang lebih sedikit dan kemudian menggunakan fasilitas pencarian yang lebih sedikit yang juga mengimplementasikan regex, untuk menyorot kemunculan kecocokan dengan pola pencarian. Argumen pencarian dalam less adalah:\<tar\> .

Pola berikutnya ini mencari "skrip shell", "program shell", "variabel shell", "lingkungan shell", atau "shell prompt" dalam dokumen pengujian kita. Tanda kurung mengubah urutan logis di mana perbandingan pola diselesaikan:

[student@studentvm1 testing]$ grep -Eni "\<shell (script|program|variable|environment|prompt)" Experiment_6-3.txt

Catatan: Artikel ini adalah versi Bab 6 yang sedikit dimodifikasi dari Volume 2 buku Linux saya, "Menggunakan dan Mengelola Linux:Nol ke SysAdmin," yang akan dirilis dari Apress pada akhir 2019.

Hapus tanda kurung dari perintah sebelumnya dan jalankan lagi untuk melihat perbedaannya.

Menutup

Meskipun sekarang kita telah menjelajahi blok penyusun dasar ekspresi reguler di grep , ada beragam cara yang tak terbatas untuk menggabungkannya untuk membuat pola pencarian yang rumit namun elegan. Namun, grep adalah alat pencarian, dan tidak menyediakan kemampuan langsung untuk mengedit atau memodifikasi baris teks dalam aliran data saat kecocokan dibuat. Untuk itu, kita membutuhkan alat seperti sed , yang akan saya bahas di artikel saya berikutnya.


Linux
  1. Mengapa Data Penting Dan Bagaimana Cara Melindunginya

  2. Potong / Grep Dan Df -h?

  3. Grep Dan Ekor -f?

  1. Vhost dan server memblokir dasar-dasar

  2. Tutorial Honeypot – Mode dan Cara Kerja Honeypot

  3. Regex (grep) untuk pencarian multi-baris diperlukan

  1. Mengekstrak dan menampilkan data dengan awk

  2. Gunakan Perintah Grep Dan Cari?

  3. grep pasang pola dan file