Mengatakan saya memiliki sebuah file:
# file: 'test.txt'
foobar bash 1
bash
foobar happy
foobar
Aku hanya ingin tahu kata-kata apa yang muncul setelah "foobar", sehingga saya bisa menggunakan regex:
"foobar \(\w\+\)"
Kurung menunjukkan bahwa saya memiliki minat khusus dalam kata-kata yang tepat setelah foobar. Tapi ketika saya melakukan grep "foobar \(\w\+\)" test.txt
saya mendapatkan seluruh baris yang cocok dengan seluruh regex, bukan hanya "kata setelah foobar":
foobar bash 1
foobar happy
Saya akan lebih memilih bahwa output dari perintah itu tampak seperti ini:
bash
happy
Apakah ada cara untuk memberitahu grep untuk hanya menampilkan item yang cocok dengan pengelompokan (atau tertentu pengelompokan) dalam ekspresi reguler?
GNU grep telah -P
pilihan untuk perl-gaya regexes, dan -o
pilihan untuk mencetak hanya apa yang sesuai dengan pola. Ini dapat dikombinasikan dengan menggunakan tampilan-sekitar asersi (dijelaskan di bawah Extended Pola di perlre halaman manual) untuk menghapus bagian dari grep pola dari apa yang ditentukan untuk memiliki cocok untuk keperluan -o
.
$ grep -oP 'foobar \K\w+' test.txt
bash
happy
$
The \K
adalah bentuk singkat (dan lebih efisien bentuk) dari (?<=pola)
yang anda gunakan sebagai nol-lebar terlihat-di balik pernyataan sebelum teks yang anda inginkan untuk output. (?=pola)
dapat digunakan sebagai nol-lebar melihat-depan pernyataan setelah teks yang anda inginkan untuk output.
Misalnya, jika anda ingin mencocokkan kata antara foo
dan bar
, anda bisa menggunakan:
$ grep -oP 'foo \K\w+(?= bar)' test.txt
atau (untuk simetri)
$ grep -oP '(?<=foo )\w+(?= bar)' test.txt
Standar grep dapat't melakukan hal ini, tapi versi terbaru dari GNU grep can. Anda dapat beralih ke sed, awk atau perl. Berikut ini adalah beberapa contoh yang melakukan apa yang anda inginkan pada sampel input; mereka berperilaku sedikit berbeda dalam kasus sudut.
Ganti foobar kata lain hal-hal
dengan kata
, mencetak hanya jika penggantian dilakukan.
sed -n -e 's/^foobar \([[:alnum:]]\+\).*/\1/p'
Jika kata pertama adalah foobar
, mencetak kedua kata.
awk '$1 == "foobar" {print $2}'
Strip foobar
jika's kata pertama, dan melewati garis lainnya; kemudian melucuti semuanya setelah spasi pertama dan cetak.
perl -lne 's/^foobar\s+// or next; s/\s.*//; print'
sed -n "s/^.*foobar\s*\(\S*\).*$/\1/p"
-n suppress printing
s substitute
^.* anything before foobar
foobar initial search match
\s* any white space character (space)
\( start capture group
\S* capture any non-white space character (word)
\) end capture group
.*$ anything after the capture group
\1 substitute everything with the 1st capture group
p print it
Jika PCRE adalah tidak didukung, anda dapat mencapai hasil yang sama dengan dua doa dari grep. Misalnya untuk ambil kata setelah foobar melakukan hal ini:
<test.txt grep -o 'foobar *[^ ]*' | grep -o '[^ ]*$'
Hal ini dapat diperluas untuk kata sewenang-wenang setelah foobar seperti ini (dengan EREs untuk dibaca):
i=1
<test.txt egrep -o 'foobar +([^ ]+ +){'$i'}[^ ]+' | grep -o '[^ ]*$'
Output:
1
Catatan indeks aku
adalah berbasis nol.
pcregrep
memiliki lebih pintar -o
pilihan
yang memungkinkan anda memilih yang menangkap kelompok-kelompok yang anda inginkan output.
Jadi, dengan menggunakan contoh file,
$ pcregrep -o1 "foobar (\w+)" test.txt
bash
happy
Menggunakan grep
tidak kompatibel cross-platform, karena -P
/--perl regexp
ini hanya tersedia pada GNU grep
, bukan BSD grep
.
Di sini adalah solusi menggunakan ripgrep
:
$ rg -o "foobar (\w+)" -r '$1' <test.txt
bash
happy
Sesuai pria rg
:
-r
/--menggantikan REPLACEMENT_TEXT
Ganti setiap pertandingan dengan teks yang diberikan.
Menangkap kelompok indeks (misalnya,
$5
) dan nama (misalnya,$foo
) yang didukung dalam string pengganti.
Terkait: GH-462.
Saya menemukan jawaban dari @jgshawkey sangat membantu. grep
tidak seperti alat yang baik untuk ini, tapi sed, meskipun di sini kita memiliki contoh yang menggunakan grep untuk ambil relevan baris.
Sintaks Regex sed lebih istimewa jika anda tidak digunakan untuk itu.
Berikut adalah contoh lain: yang satu ini mem-parsing output dari xinput untuk mendapatkan ID integer
⎜ ↳ SynPS/2 Synaptics TouchPad id=19 [slave pointer (2)]
dan aku ingin 19
export TouchPadID=$(xinput | grep 'TouchPad' | sed -n "s/^.*id=\([[:digit:]]\+\).*$/\1/p")
Catatan kelas sintaks:
[[:digit:]]
dan kebutuhan untuk melarikan diri berikut +
Saya mengasumsikan hanya satu garis pertandingan.