Terkadang (dalam kasus sederhana) dimungkinkan untuk menyesuaikan pemisah bidang ( FS) dan memilih yang ingin dicocokkan dengan a $field. Memformat ulang input juga dapat membantu.
Rupanya seseorang tidak setuju. Halaman web ini dari 2005: tek-tips.com/faqs.cfm?fid=5674 Ini menegaskan bahwa Anda tidak dapat menggunakan kembali grup yang cocok di awk.
Peter Tillemans
3
Saya lebih suka 'perl -n -p -e ...' daripada awk untuk hampir semua kasus penggunaan, karena lebih fleksibel, lebih kuat dan memiliki sintaks yang lebih waras menurut saya.
Peter Tillemans
15
gawk! = awk. Mereka adalah alat yang berbeda dan gawktidak tersedia secara default di sebagian besar tempat.
Oli
6
OP secara khusus meminta solusi awk, jadi saya rasa ini bukan jawaban.
Joppe
6
@Joppe Anda tidak dapat memberikan solusi awk jika tidak ada solusi. Di baris 3 saya jelaskan bahwa AWK tidak mendukung kelompok penangkap dan saya memberikan alternatif, yang tampaknya dihargai OP karena jawaban ini diterima. Bagaimana saya bisa menjawab pertanyaan ini dengan lebih baik?
Peter Tillemans
335
Dengan gawk, Anda dapat menggunakan matchfungsi ini untuk menangkap grup yang diurung.
gawk 'match($0, pattern, ary) {print ary[1]}'
contoh:
echo "abcdef"| gawk 'match($0, /b(.*)e/, a) {print a[1]}'
output cd.
Perhatikan penggunaan spesifik dari gawk yang mengimplementasikan fitur yang dimaksud.
Untuk alternatif portabel Anda dapat mencapai hasil yang serupa dengan match()dan substr.
@ bfontaine Bisakah grep -omenampilkan grup yang ditangkap?
Olle Härstedt
1
@ OlleHärstedt Tidak, tidak bisa. Ini hanya mencakup kasus penggunaan Anda ketika Anda tidak memiliki kelompok tangkapan. Dalam hal itu menjadi jelek dengan rantai grep -o.
Anda dapat mensimulasikan menangkap vanila awk juga, tanpa ekstensi. Itu tidak intuitif:
langkah 1. gunakan gensub untuk mengelilingi kecocokan dengan beberapa karakter yang tidak muncul di string Anda. langkah 2. Gunakan split terhadap karakter. langkah 3. Setiap elemen lain dalam array yang dibelah adalah grup tangkapan Anda.
$ echo 'ab cb ad' | awk '{split (gensub (/ a ./, SUBSEP "&" SUBSEP, "g", $ 0), cap, SUBSEP); tutup cetak [2] "|" cap [4]; } '
ab | iklan
Saya hampir yakin itu gensubadalah gawkfungsi spesifik. Apa yang Anda dapatkan dari pekerjaan Anda jika Anda mengetik awk --version; -?). Semoga beruntung untuk semua.
shellter
6
Saya sepenuhnya yakin bahwa gensub adalah gawk-isme, meskipun BusyBox awk juga memilikinya. Jawaban ini juga dapat diimplementasikan menggunakan gsub, meskipun:echo 'ab cb ad' | awk '{gsub(/a./,SUBSEP"&"SUBSEP);split($0,cap,SUBSEP);print cap[2]"|"cap[4]}'
dubiousjim
3
gensub () adalah ekstensi gawk, manual gawk jelas mengatakannya. Varian awk lain mungkin juga mengimplementasikannya, tetapi masih belum POSIX. Coba gawk --posix '{gsub (...)}' dan itu akan mengeluh
MestreLion
2
@MestreLion, maksud Anda akan mengadu gawk --posix '{gensub(...)}'.
dubiousjim
1
Meskipun Anda salah tentang POSIX awk yang memiliki gensubfungsi, contoh Anda diterapkan pada skenario yang sangat terbatas: seluruh pola dikelompokkan, itu tidak dapat cocok dengan sesuatu seperti semua key=(value)ketika saya ingin mengekstrak hanya valuebagian - bagiannya.
Meow
2
Saya sedikit berjuang dengan menghasilkan fungsi bash yang membungkus jawaban Peter Tillemans tetapi inilah yang saya kemukakan:
function regex {perl -n -e "/ $ 1 / && printf \"% s \ n \ "," '$ 1'}
Saya menemukan ini bekerja lebih baik daripada fungsi bash berbasis aws opsb untuk argumen ekspresi reguler berikut, karena saya tidak ingin "ms" dicetak.
Saya lebih suka solusi ini, karena Anda dapat melihat bagian-bagian kelompok yang membatasi penangkapan, sementara juga menghilangkannya. Namun, dapatkah seseorang menjelaskan cara kerjanya? Saya tidak bisa mendapatkan sintaks perl ini berfungsi dengan baik di BASH, karena saya tidak memahaminya dengan baik - terutama tanda kutip ganda / tunggal di sekitar$1
Demis
Ini bukan sesuatu yang telah saya lakukan sebelum atau sesudahnya, tetapi melihat ke belakang apa yang dilakukannya adalah merangkai dua string, string pertama berada dalam tanda kutip ganda (string pertama ini berisi tanda kutip ganda tertanam yang lolos dengan garis miring terbalik) dan string kedua berada dalam tanda kutip tunggal . Kemudian hasil dari rangkaian itu diberikan sebagai argumen untuk perl -e. Anda juga perlu tahu bahwa $ 1 pertama (yang dalam tanda kutip ganda) diganti dengan argumen pertama ke fungsi, sedangkan $ 1 kedua (yang dalam tanda kutip tunggal) dibiarkan tidak tersentuh. Lihat contoh ini
wytten
Saya mengerti, itu lebih masuk akal sekarang. Jadi di mana di perintah perl definisi regex match / group capture? Saya melihat Anda menulis '([0-9]*)ms$'- apakah itu disediakan sebagai argumen (dan string argumen lain)? Dan output dari perl -esedang dimasukkan ke dalam printfperintah bash kemudian, untuk menggantikannya %s, apakah itu benar? Terima kasih, saya berharap bisa menggunakan ini.
Demis
1
Anda memberikan ekspresi reguler yang dilampirkan dalam tanda kutip tunggal sebagai satu-satunya argumen untuk fungsi bash regex. Contoh
FS
) dan memilih yang ingin dicocokkan dengan a$field
. Memformat ulang input juga dapat membantu.gawk
(karena menggunakangensub
).Jawaban:
Itu berjalan-jalan di jalur memori ...
Saya menggantikan awk dengan perl sejak lama.
Rupanya mesin ekspresi reguler AWK tidak menangkap kelompoknya.
Anda mungkin mempertimbangkan untuk menggunakan sesuatu seperti:
flag -n menyebabkan perl untuk mengulangi setiap baris seperti awk.
sumber
gawk
! =awk
. Mereka adalah alat yang berbeda dangawk
tidak tersedia secara default di sebagian besar tempat.Dengan gawk, Anda dapat menggunakan
match
fungsi ini untuk menangkap grup yang diurung.contoh:
output
cd
.Perhatikan penggunaan spesifik dari gawk yang mengimplementasikan fitur yang dimaksud.
Untuk alternatif portabel Anda dapat mencapai hasil yang serupa dengan
match()
dansubstr
.contoh:
output
cd
.sumber
Ini adalah sesuatu yang saya butuhkan sepanjang waktu jadi saya membuat fungsi bash untuknya. Ini berdasarkan jawaban glenn jackman.
Definisi
Tambahkan ini ke .bash_profile Anda dll.
Pemakaian
Abadikan regex untuk setiap baris dalam file
Capture 1st regex capture group untuk setiap baris dalam file
sumber
grep -o
?grep -o
menampilkan grup yang ditangkap?grep -o
.Anda dapat menggunakan GNU awk:
sumber
awk 'match($0, /.*(http.*?)\$/) { print substr($0,RSTART,RLENGTH) }'
RewriteRule (.*) http://www.mysite.net/$
untuk saya, yang lebih dari subkelompok.RSTART
danRLENGTH
merujuk ke substring yang cocok dengan polaAnda dapat mensimulasikan menangkap vanila awk juga, tanpa ekstensi. Itu tidak intuitif:
langkah 1. gunakan gensub untuk mengelilingi kecocokan dengan beberapa karakter yang tidak muncul di string Anda. langkah 2. Gunakan split terhadap karakter. langkah 3. Setiap elemen lain dalam array yang dibelah adalah grup tangkapan Anda.
sumber
gensub
adalahgawk
fungsi spesifik. Apa yang Anda dapatkan dari pekerjaan Anda jika Anda mengetikawk --version
; -?). Semoga beruntung untuk semua.echo 'ab cb ad' | awk '{gsub(/a./,SUBSEP"&"SUBSEP);split($0,cap,SUBSEP);print cap[2]"|"cap[4]}'
gawk --posix '{gensub(...)}'
.gensub
fungsi, contoh Anda diterapkan pada skenario yang sangat terbatas: seluruh pola dikelompokkan, itu tidak dapat cocok dengan sesuatu seperti semuakey=(value)
ketika saya ingin mengekstrak hanyavalue
bagian - bagiannya.Saya sedikit berjuang dengan menghasilkan fungsi bash yang membungkus jawaban Peter Tillemans tetapi inilah yang saya kemukakan:
Saya menemukan ini bekerja lebih baik daripada fungsi bash berbasis aws opsb untuk argumen ekspresi reguler berikut, karena saya tidak ingin "ms" dicetak.
sumber
$1
'([0-9]*)ms$'
- apakah itu disediakan sebagai argumen (dan string argumen lain)? Dan output dariperl -e
sedang dimasukkan ke dalamprintf
perintah bash kemudian, untuk menggantikannya%s
, apakah itu benar? Terima kasih, saya berharap bisa menggunakan ini.