Saya sedang belajar Linux, dan saya punya tantangan yang sepertinya tidak bisa saya selesaikan sendiri. Ini dia:
grep baris dari file yang berisi 4 angka berturut-turut tetapi tidak lebih dari 4.
Saya tidak yakin bagaimana mendekati ini. Saya dapat mencari angka-angka tertentu tetapi bukan jumlahnya dalam suatu string.
1234a12345
ditampilkan, atau tidak?\b\d{4}\b
Jawaban:
Ada dua cara untuk menafsirkan pertanyaan ini; Saya akan membahas kedua kasus ini. Anda mungkin ingin menampilkan garis:
Misalnya, (1) akan ditampilkan
1234a56789
, tetapi (2) tidak.Jika Anda ingin menampilkan semua baris yang berisi urutan empat digit yang dengan sendirinya bukan bagian dari urutan digit yang lebih lama, salah satu caranya adalah:
Ini menggunakan ekspresi reguler Perl , yang didukung oleh Ubuntu
grep
( GNU grep )-P
. Itu tidak akan cocok dengan teks suka12345
, juga tidak akan cocok dengan1234
atau2345
yang merupakan bagian dari itu. Tapi itu akan cocok dengan1234
in1234a56789
.Dalam ekspresi reguler Perl:
\d
berarti angka apa saja (ini adalah cara singkat untuk mengatakan[0-9]
atau[[:digit:]]
).x{4}
cocokx
4 kali. ({
}
Sintaks tidak khusus untuk ekspresi reguler Perl; itu dalam ekspresi reguler yang diperluasgrep -E
juga.) Begitu\d{4}
juga dengan\d\d\d\d
.(?<!\d)
adalah pernyataan pandangan ke belakang negatif lebar nol. Itu berarti "kecuali didahului oleh\d
."(?!\d)
adalah pernyataan pandangan ke depan negatif lebar nol. Itu berarti "kecuali diikuti oleh\d
."(?<!\d)
dan(?!\d)
jangan mencocokkan teks di luar urutan empat digit; alih-alih, mereka akan (saat digunakan bersama-sama) mencegah urutan empat digit dari dirinya sendiri dicocokkan jika itu adalah bagian dari urutan angka yang lebih panjang.Menggunakan hanya melihat-belakang atau hanya melihat-depan tidak cukup karena urutan empat digit paling kanan atau paling kiri masih akan cocok.
Salah satu manfaat menggunakan pernyataan lihat-belakang dan lihat-depan adalah bahwa pola Anda hanya cocok dengan urutan empat digit itu sendiri, dan bukan teks di sekitarnya. Ini bermanfaat saat menggunakan penyorotan warna (dengan
--color
opsi).Secara default di Ubuntu, setiap pengguna memiliki file
alias grep='grep --color=auto'
mereka . Jadi Anda mendapatkan penyorotan warna secara otomatis ketika Anda menjalankan perintah sederhana dimulai dengan (ini adalah saat alias diperluas) dan output standar adalah terminal (inilah yang memeriksa). Cocok biasanya disorot dalam warna merah (dekat dengan vermilion ), tetapi saya telah menunjukkannya dalam huruf miring dicetak tebal. Berikut screenshotnya:~.bashrc
grep
--color=auto
Dan Anda bahkan dapat membuat
grep
cetak hanya teks yang cocok, dan bukan seluruh baris, dengan-o
:Cara Alternatif, Tanpa Tegas dan Tegas
Namun, jika Anda:
grep
tidak mendukung-P
atau tidak ingin menggunakan ekspresi reguler Perl, dan... maka Anda dapat mencapai ini dengan ekspresi reguler yang diperluas sebagai gantinya:
Ini cocok dengan empat digit dan karakter non-digit - atau awal atau akhir garis - yang mengelilinginya. Secara khusus:
[0-9]
cocok dengan digit mana pun (seperti[[:digit:]]
, atau\d
dalam ekspresi reguler Perl) dan{4}
berarti "empat kali." Jadi[0-9]{4}
cocok dengan urutan empat digit.[^0-9]
cocok dengan karakter yang tidak berada dalam kisaran0
melalui9
. Ini sama dengan[^[:digit:]]
(atau\D
, dalam ekspresi reguler Perl).^
, ketika itu tidak muncul dalam[
]
tanda kurung, cocok dengan awal baris. Demikian pula,$
cocok dengan akhir garis.|
berarti atau dan tanda kurung untuk pengelompokan (seperti dalam aljabar). Jadi(^|[^0-9])
cocok dengan awal baris atau karakter non-digit, sementara($|[^0-9])
cocok dengan akhir baris atau karakter non-digit.Jadi kecocokan hanya terjadi pada garis yang berisi urutan empat digit (
[0-9]{4}
) yang secara bersamaan:(^|[^0-9])
), dan($|[^0-9])
).Jika, di sisi lain, Anda ingin menampilkan semua baris yang mengandung urutan empat digit, tetapi tidak mengandung salah urutan lebih dari empat digit (bahkan salah satu yang terpisah dari urutan lain dari hanya empat digit), maka secara konseptual Anda tujuannya adalah menemukan garis yang cocok dengan satu pola tetapi tidak yang lain.
Oleh karena itu, bahkan jika Anda tahu bagaimana melakukannya dengan pola tunggal, saya sarankan menggunakan sesuatu seperti saran kedua matt ,
grep
untuk dua pola secara terpisah.Anda tidak mendapatkan banyak manfaat dari fitur lanjutan dari ekspresi reguler Perl saat melakukan itu, jadi Anda mungkin memilih untuk tidak menggunakannya. Namun sesuai dengan gaya di atas, berikut adalah pemendekan dari solusi matt menggunakan
\d
(dan kawat gigi) sebagai pengganti[0-9]
:Sejak digunakan
[0-9]
, cara matt lebih portabel - ini akan bekerja pada sistem yanggrep
tidak mendukung ekspresi reguler Perl. Jika Anda menggunakan[0-9]
(atau[[:digit:]]
) alih-alih\d
, tetapi terus menggunakan{
}
, Anda mendapatkan portabilitas cara matt sedikit lebih ringkas:Cara Alternatif, Dengan Pola Tunggal
Jika Anda benar-benar lebih suka
grep
perintah itugrep
s dipisahkan oleh pipa , seperti di atas)... maka Anda dapat menggunakan:
The
-x
merek benderagrep
hanya menampilkan garis-garis di mana seluruh pertandingan line (bukan setiap baris mengandung pertandingan).Saya telah menggunakan ekspresi reguler Perl karena saya pikir singkatnya
\d
dan\D
secara substansial meningkatkan kejelasan dalam kasus ini. Tetapi jika Anda membutuhkan sesuatu yang portabel untuk sistem yanggrep
tidak mendukung-P
, Anda dapat menggantinya dengan[0-9]
dan[^0-9]
(atau dengan[[:digit:]]
dan[^[:digit]]
):Cara kerja ekspresi reguler ini adalah:
Di tengah,
\d{4}
atau[0-9]{4}
cocok dengan satu urutan empat digit. Kita mungkin memiliki lebih dari satu, tetapi kita harus memiliki setidaknya satu.Di sebelah kiri,
(\d{0,4}\D)*
atau([0-9]{0,4}[^0-9])*
cocok dengan nol atau lebih (*
) contoh tidak lebih dari empat digit diikuti oleh non-digit. Nol digit (yaitu, tidak ada) adalah satu kemungkinan untuk "tidak lebih dari empat digit." Ini cocok dengan (a) string kosong atau (b) string yang diakhiri dengan non-digit dan tidak mengandung urutan lebih dari empat digit.Karena teks tepat di sebelah kiri tengah
\d{4}
(atau[0-9]{4}
) harus kosong atau diakhiri dengan non-digit, ini mencegah pusat\d{4}
dari mencocokkan empat digit yang memiliki digit (kelima) lainnya tepat di sebelah kiri mereka.Di sebelah kanan,
(\D\d{0,4})*
atau([^0-9][0-9]{0,4})*
cocok dengan nol atau lebih (*
) contoh non-digit diikuti oleh tidak lebih dari empat digit (yang, seperti sebelumnya, bisa empat, tiga, dua, satu, atau bahkan tidak sama sekali). Ini cocok dengan (a) string kosong atau (b) string yang dimulai dengan non-digit dan tidak mengandung urutan lebih dari empat digit.Karena teks segera di sebelah kanan pusat
\d{4}
(atau[0-9]{4}
) harus kosong atau mulai dengan non-digit, ini mencegah pusat\d{4}
dari mencocokkan empat digit yang memiliki digit (kelima) lainnya tepat di sebelah kanannya.Ini memastikan empat digit urutan hadir di suatu tempat, dan tidak ada urutan lima digit atau lebih yang hadir di mana saja.
Tidak buruk atau salah melakukannya dengan cara ini. Tetapi mungkin alasan paling penting untuk mempertimbangkan alternatif ini adalah bahwa ia mengklarifikasi manfaat menggunakan (atau serupa) sebagai gantinya, seperti yang disarankan di atas dan dalam jawaban matt .
grep -P '\d{4}' file | grep -Pv '\d{5}'
Dengan cara itu, jelas tujuan Anda adalah memilih garis yang berisi satu hal tetapi bukan yang lain. Plus sintaksinya lebih sederhana (sehingga mungkin lebih cepat dipahami oleh banyak pembaca / pengelola).
sumber
Ini akan menunjukkan kepada Anda 4 angka berturut-turut tetapi tidak lebih
Perhatikan ^ artinya tidak
Ada masalah dengan ini meskipun saya tidak yakin bagaimana cara memperbaikinya ... jika angkanya adalah akhir dari baris maka tidak akan muncul.
Namun versi yang lebih buruk ini akan bekerja untuk kasus itu
sumber
a12345b
, karena cocok2345b
.Jika
grep
tidak mendukung perl regular expressions (-P
), gunakan perintah shell berikut:dimana
printf '[0-9]%.0s' {1..4}
akan menghasilkan 4 kali[0-9]
. Metode ini berguna, ketika Anda memiliki angka yang panjang dan Anda tidak ingin mengulangi polanya (cukup ganti4
dengan jumlah digit Anda untuk mencari).Menggunakan
-w
akan mencari seluruh kata. Namun jika Anda tertarik pada string alfanumerik, seperti1234a
, lalu tambahkan[^0-9]
di akhir pola, misMenggunakan
$()
pada dasarnya adalah substitusi perintah . Periksa pos ini untuk melihat bagaimanaprintf
pengulangan pola.sumber
Anda dapat mencoba perintah di bawah ini dengan mengganti
file
dengan nama file aktual di sistem Anda:Anda juga dapat memeriksa tutorial ini untuk lebih banyak menggunakan perintah grep.
sumber