Czasami (w prostych przypadkach) możliwe jest dostosowanie separatora pól ( FS) i wybranie, z którym chcesz dopasować $field. Wstępne formatowanie danych wejściowych również może pomóc.
Najwyraźniej ktoś się nie zgadza. Ta strona internetowa pochodzi z 2005 roku: tek-tips.com/faqs.cfm?fid=5674 Potwierdza, że nie można ponownie używać dopasowanych grup w awk.
Peter Tillemans
3
Wolę „perl -n -p -e ...” niż awk dla prawie wszystkich przypadków użycia, ponieważ jest on bardziej elastyczny, potężniejszy i ma bardziej rozsądną składnię.
Peter Tillemans
15
gawk! = awk. Są to różne narzędzia i gawknie są domyślnie dostępne w większości miejsc.
Oli
6
OP specjalnie poprosił o rozwiązanie awk, więc nie sądzę, że to odpowiedź.
Joppe
6
@Joppe nie możesz dać rozwiązania awk, jeśli nie ma rozwiązania. W wierszu 3 wyjaśniam, że AWK nie obsługuje przechwytywania grup i podałem alternatywę, którą PO najwyraźniej docenił, ponieważ odpowiedź została zaakceptowana. Jak mógłbym lepiej odpowiedzieć na to pytanie?
Peter Tillemans,
335
Z gawk możesz użyć matchfunkcji do przechwytywania grup w nawiasach.
gawk 'match($0, pattern, ary) {print ary[1]}'
przykład:
echo "abcdef"| gawk 'match($0, /b(.*)e/, a) {print a[1]}'
wyjścia cd.
Zwróć uwagę na szczególne zastosowanie gawk, który implementuje tę funkcję.
W przypadku przenośnej alternatywy możesz osiągnąć podobne wyniki za pomocą match()i substr.
@bfontaine Czy można grep -owysyłać przechwycone grupy?
Olle Härstedt,
1
@ OlleHärstedt Nie, nie można. Dotyczy tylko przypadku użycia, gdy nie masz grup przechwytywania. W takim przypadku robi się brzydko z łańcuchami grep -o.
Ed Morton: powiedziałbym, że zasługuje na najwyższą odpowiedź. edit: uhm ... to drukuje RewriteRule (.*) http://www.mysite.net/$dla mnie, co jest czymś więcej niż podgrupą.
Możesz także symulować przechwytywanie w waniliowym awk, bez rozszerzeń. Nie jest to jednak intuicyjne:
krok 1. użyj gensub, aby otaczać dopasowania niektórymi znakami, które nie pojawiają się w ciągu. krok 2. Użyj podziału przeciwko postaci. krok 3. Każdy inny element w podzielonej tablicy to twoja grupa przechwytywania.
$ echo 'ab cb ad' | awk '{split (gensub (/ a ./, SUBSEP "&" SUBSEP, "g", 0 $), cap, SUBSEP); czapka z daszkiem [2] „|” czapka [4]; } ”
ab | ad
Jestem prawie pewien, że gensubjest to gawkspecyficzna funkcja. Co otrzymasz z awk, jeśli wpiszesz awk --version; -?). Powodzenia wszystkim.
shellter
6
Jestem całkowicie pewien, że gensub jest gawk-izmem, chociaż awy BusyBox też go ma. Ta odpowiedź może być również zaimplementowana przy użyciu gsub, jednak:echo 'ab cb ad' | awk '{gsub(/a./,SUBSEP"&"SUBSEP);split($0,cap,SUBSEP);print cap[2]"|"cap[4]}'
dubiousjim
3
gensub () jest rozszerzeniem gawk, instrukcja gawk wyraźnie to mówi. Inne warianty awk również mogą to zaimplementować, ale wciąż nie jest to POSIX. Spróbuj gawk --posix '{gsub (...)}', a będzie narzekać
MestreLion
2
@MestreLion, masz na myśli, że będzie narzekać gawk --posix '{gensub(...)}'.
dubiousjim
1
Pomimo tego, że myliłeś się co do tego, że POSIX awk ma tę gensubfunkcję, twój przykład zastosował się do bardzo ograniczonego scenariusza: cały wzorzec jest zgrupowany, nie może pasować do czegoś podobnego, key=(value)gdy chcę wyodrębnić tylko valueczęści.
Miau
2
Zmagałem się trochę z wymyśleniem funkcji bash, która otacza odpowiedź Petera Tillemansa, ale oto co wymyśliłem:
funkcja regex {perl -n -e "/ $ 1 / && printf \"% s \ n \ "," '$ 1'}
Okazało się, że działało to lepiej niż oparta na awk funkcja bash opsb dla następującego argumentu wyrażenia regularnego, ponieważ nie chcę, aby drukowano ms
Wolę to rozwiązanie, ponieważ możesz zobaczyć części grupy, które ograniczają przechwytywanie, jednocześnie je pomijając. Czy jednak ktoś mógłby wyjaśnić, jak to działa? Nie mogę sprawić, by ta składnia perla działała poprawnie w BASH, ponieważ nie rozumiem jej zbyt dobrze - szczególnie podwójne / pojedyncze cudzysłowy wokół$1
Demis
Nie jest to coś, co zrobiłem wcześniej lub później, ale patrząc wstecz, to, co robi, to łączenie dwóch ciągów, pierwszy ciąg jest w podwójnych cudzysłowach (ten pierwszy ciąg zawiera osadzone podwójne cudzysłowy, które ucieka się odwrotnym ukośnikiem), a drugi ciąg jest w pojedynczych cudzysłowach . Następnie wynik tej konkatenacji jest dostarczany jako argument do perla -e. Musisz także wiedzieć, że pierwszy $ 1 (ten w cudzysłowie) jest zastąpiony pierwszym argumentem funkcji, podczas gdy drugi $ 1 (ten w cudzysłowie) pozostaje nietknięty. Zobacz ten przykład
wytten
Rozumiem, to ma teraz trochę więcej sensu. Gdzie więc w poleceniu perl jest definicja dopasowania / wyrażenia regularnego wyrażenia regularnego? Widzę, że napisałeś '([0-9]*)ms$'- czy jest podany jako argument (a ciąg inny argument)? A wynik perl -ejest wstawiany do printfpolecenia bash , aby zastąpić %s, prawda? Dzięki, mam nadzieję to wykorzystać.
Demis,
1
Jako jedyny argument funkcji regularnego wyrażenia regularnego przekazujesz wyrażenie regularne ujęte w pojedyncze cudzysłowy. Przykład
FS
) i wybranie, z którym chcesz dopasować$field
. Wstępne formatowanie danych wejściowych również może pomóc.gawk
(ponieważ używagensub
).Odpowiedzi:
To był spacer ścieżką pamięci ...
Dawno temu zastąpiłem awk Perlem.
Najwyraźniej silnik wyrażeń regularnych AWK nie przechwytuje jego grup.
możesz rozważyć użycie czegoś takiego:
flaga -n powoduje, że perl zapętla każdą linię, tak jak robi to awk.
źródło
gawk
! =awk
. Są to różne narzędzia igawk
nie są domyślnie dostępne w większości miejsc.Z gawk możesz użyć
match
funkcji do przechwytywania grup w nawiasach.przykład:
wyjścia
cd
.Zwróć uwagę na szczególne zastosowanie gawk, który implementuje tę funkcję.
W przypadku przenośnej alternatywy możesz osiągnąć podobne wyniki za pomocą
match()
isubstr
.przykład:
wyjścia
cd
.źródło
Potrzebuję tego cały czas, więc stworzyłem dla niego funkcję bash. Opiera się na odpowiedzi Glenna Jackmana.
Definicja
Dodaj to do swojego .bash_profile itp.
Stosowanie
Przechwyć wyrażenie regularne dla każdej linii w pliku
Przechwyć pierwszą grupę przechwytywania wyrażeń regularnych dla każdej linii w pliku
źródło
grep -o
?grep -o
wysyłać przechwycone grupy?grep -o
.Możesz użyć GNU awk:
źródło
awk 'match($0, /.*(http.*?)\$/) { print substr($0,RSTART,RLENGTH) }'
RewriteRule (.*) http://www.mysite.net/$
dla mnie, co jest czymś więcej niż podgrupą.RSTART
iRLENGTH
odnosi się do niegoMożesz także symulować przechwytywanie w waniliowym awk, bez rozszerzeń. Nie jest to jednak intuicyjne:
krok 1. użyj gensub, aby otaczać dopasowania niektórymi znakami, które nie pojawiają się w ciągu. krok 2. Użyj podziału przeciwko postaci. krok 3. Każdy inny element w podzielonej tablicy to twoja grupa przechwytywania.
źródło
gensub
jest togawk
specyficzna funkcja. Co otrzymasz z awk, jeśli wpiszeszawk --version
; -?). Powodzenia wszystkim.echo 'ab cb ad' | awk '{gsub(/a./,SUBSEP"&"SUBSEP);split($0,cap,SUBSEP);print cap[2]"|"cap[4]}'
gawk --posix '{gensub(...)}'
.gensub
funkcję, twój przykład zastosował się do bardzo ograniczonego scenariusza: cały wzorzec jest zgrupowany, nie może pasować do czegoś podobnego,key=(value)
gdy chcę wyodrębnić tylkovalue
części.Zmagałem się trochę z wymyśleniem funkcji bash, która otacza odpowiedź Petera Tillemansa, ale oto co wymyśliłem:
Okazało się, że działało to lepiej niż oparta na awk funkcja bash opsb dla następującego argumentu wyrażenia regularnego, ponieważ nie chcę, aby drukowano ms
źródło
$1
'([0-9]*)ms$'
- czy jest podany jako argument (a ciąg inny argument)? A wynikperl -e
jest wstawiany doprintf
polecenia bash , aby zastąpić%s
, prawda? Dzięki, mam nadzieję to wykorzystać.