Katakanlah saya punya file:
# file: 'test.txt'
foobar bash 1
bash
foobar happy
foobar
Saya hanya ingin tahu kata-kata apa yang muncul setelah "foobar", jadi saya bisa menggunakan regex ini:
"foobar \(\w\+\)"
Tanda kurung menunjukkan bahwa saya memiliki minat khusus pada kata setelah foobar. Tetapi ketika saya melakukan grep "foobar \(\w\+\)" test.txt
, saya mendapatkan seluruh baris yang cocok dengan seluruh regex, daripada hanya "kata setelah foobar":
foobar bash 1
foobar happy
Saya lebih suka output dari perintah itu terlihat seperti ini:
bash
happy
Apakah ada cara untuk memberi tahu grep agar hanya menampilkan item yang cocok dengan pengelompokan (atau pengelompokan tertentu) dalam ekspresi reguler?
text-processing
grep
regular-expression
Cory Klein
sumber
sumber
perl -lne 'print $1 if /foobar (\w+)/' < test.txt
Jawaban:
GNU grep memiliki
-P
opsi untuk reg-style perl, dan-o
opsi untuk hanya mencetak apa yang cocok dengan polanya. Ini dapat digabungkan dengan menggunakan pernyataan melihat-lihat (dijelaskan dalam Pola Diperluas dalam halaman perlre ) untuk menghapus bagian dari pola grep dari apa yang ditentukan telah cocok untuk keperluan-o
.Ini
\K
adalah bentuk pendek (dan bentuk yang lebih efisien)(?<=pattern)
yang Anda gunakan sebagai pernyataan melihat ke belakang lebar nol sebelum teks yang ingin Anda hasilkan.(?=pattern)
dapat digunakan sebagai pernyataan melihat ke depan dengan lebar nol setelah teks yang ingin Anda hasilkan.Misalnya, jika Anda ingin mencocokkan kata antara
foo
danbar
, Anda dapat menggunakan:atau (untuk simetri)
sumber
sed(1)
grep -oP 'foobar \K\w+' test.txt
tidak menghasilkan apa-apa dengan OPtest.txt
. Versi grep adalah 2.5.1. Apa yang salah? O_OGrep standar tidak dapat melakukan ini, tetapi versi terbaru dari GNU grep bisa . Anda dapat beralih ke sed, awk atau perl. Berikut adalah beberapa contoh yang melakukan apa yang Anda inginkan pada input sampel Anda; mereka berperilaku sedikit berbeda dalam kasus sudut.
Ganti
foobar word other stuff
denganword
, cetak hanya jika penggantian dilakukan.Jika kata pertama adalah
foobar
, cetak kata kedua.Lepas
foobar
jika itu kata pertama, dan lewati saja; kemudian strip semua setelah spasi putih dan cetak.sumber
grep
. Tapi sintaks untuk perintah-perintah ini sebenarnya terlihat sangat akrab sekarang karena saya sudah terbiasa dengan pencarian gaya vim & ganti + regex. Terima kasih banyak.grep
tidak memiliki dukungan PCRE.sumber
^
dan$
karena itu.*
adalah pertandingan serakah. Namun, termasuk mereka dapat membantu memperjelas maksud regex.Nah, jika Anda tahu bahwa foobar selalu merupakan kata atau baris pertama, maka Anda dapat menggunakan cut. Seperti itu:
sumber
-o
switch on grep secara luas diterapkan (lebih dari ekstensi grep Gnu), demikiangrep -o "foobar" test.file | cut -d" " -f2
akan meningkatkan efektivitas dari solusi ini, yang lebih portabel daripada menggunakan pernyataan lookbehind.grep -o "foobar .*
"ataugrep -o "foobar \w+"
.Jika PCRE tidak didukung, Anda dapat mencapai hasil yang sama dengan dua pemanggilan grep. Misalnya untuk mengambil kata setelah foobar lakukan ini:
Ini dapat diperluas ke kata arbitrer setelah foobar seperti ini (dengan ERE agar mudah dibaca):
Keluaran:
Perhatikan indeks
i
berbasis nol.sumber
pcregrep
memiliki-o
opsi yang lebih cerdas yang memungkinkan Anda memilih grup menangkap mana yang Anda inginkan. Jadi, menggunakan file contoh Anda,sumber
Menggunakan
grep
tidak kompatibel lintas platform, karena-P
/--perl-regexp
hanya tersedia di GNUgrep
, bukan BSDgrep
.Inilah solusinya menggunakan
ripgrep
:Sesuai
man rg
:Terkait: GH-462 .
sumber
Saya menemukan jawaban @jgshawkey sangat membantu.
grep
bukan alat yang baik untuk ini, tetapi sed adalah, meskipun di sini kita memiliki contoh yang menggunakan grep untuk mengambil garis yang relevan.Sintaks regex dari sed adalah istimewa jika Anda tidak terbiasa.
Berikut adalah contoh lain: yang ini mem-parsing output xinput untuk mendapatkan ID integer
dan saya ingin 19
Perhatikan sintaks kelas:
dan kebutuhan untuk melarikan diri dari yang berikut
+
Saya menganggap hanya satu baris yang cocok.
sumber
grep
, dengan anggapan 'TouchPad' ada di sebelah kiri 'id':echo "SynPS/2 Synaptics TouchPad id=19 [slave pointer (2)]" | sed -nE "s/.*TouchPad.+id=([0-9]+).*/\1/p"