Używanie wielu ograniczników w awk

202

Mam plik zawierający następujące wiersze:

/logs/tc0001/tomcat/tomcat7.1/conf/catalina.properties:app.env.server.name = demo.example.com
/logs/tc0001/tomcat/tomcat7.2/conf/catalina.properties:app.env.server.name = quest.example.com
/logs/tc0001/tomcat/tomcat7.5/conf/catalina.properties:app.env.server.name = www.example.com

W powyższym wyjściu chcę wyodrębnić 3 pola (numer 2, 4 i ostatnie *.example.com). Otrzymuję następujące dane wyjściowe:

cat file | awk -F'/' '{print $3 "\t" $5}'
tc0001   tomcat7.1
tc0001   tomcat7.2
tc0001   tomcat7.5

Jak wyodrębnić ostatnie pole z nazwą domeny, która jest później '='? Jak użyć multiple delimiterdo wyodrębnienia pola?

Satish
źródło
2
Aby odpowiedzieć na moje pytanie, które jest takie samo, ale inne, awkprzełykałem pola, gdy były puste, co oznaczało numerację pól. Zmieniłem -F " "się -F "[ ]"i awkjuż nie połykałem pustych pól.
Adam

Odpowiedzi:

324

Separator może być wyrażeniem regularnym.

awk -F'[/=]' '{print $3 "\t" $5 "\t" $8}' file

Produkuje:

tc0001   tomcat7.1    demo.example.com  
tc0001   tomcat7.2    quest.example.com  
tc0001   tomcat7.5    www.example.com
embedded.kyle
źródło
42
Oczywiście, catproces ten nie jest wymagane: awk '...' file. Również bardziej pomocne byłoby użycie separatora pola wyjściowego:awk -F'[/=]' -v OFS="\t" '{print $3, $5, $8}'
glenn jackman
17
Ograniczniki Awk mogą być wyrażeniami regularnymi ... to sprawiło, że mój dzień!
das.cyklone
4
@ das.cyklone: awk może mieć również kilka separatorów, z |: Ex: awk -F 'this|that|[=/]' '......' (usefull mieć słów / łańcuchy oddzielające rzeczy) (uwaga, że ta utrzymuje przestrzenie w fiels między 2 separatory Dodawanie również. |[ \t]+mogą być przydatne, ale można zrobić rzeczy trudne ... ponieważ przed i po tym są często spacje, między tymi polami i „tym” pojawią się 2 dodatkowe puste pola
Olivier Dulac
Próbowałem tego na 2 różnych dystrybucjach i mam takie samo zachowanie: Chcę uzyskać port z netstat -ntpl "netstat -ntpl | sed 's /: / /' | awk '{print $ 5}'” działa, ale da się obejść bez instalacji doulbe Działa to, ale nie spodziewałem się danych w polu 17: "netstat -ntpl | awk -F" |: "'{print 17 $}'"
louigi600
2
tak ... dostałem to, czego chciałem: awk -F "[:] +" '/ \ / postmaster * $ / {print $ 5}'
louigi600
44

Dobre wieści! awkseparator pól może być wyrażeniem regularnym. Musisz tylko użyć -F"<separator1>|<separator2>|...":

awk -F"/|=" -vOFS='\t' '{print $3, $5, $NF}' file

Zwroty:

tc0001  tomcat7.1  demo.example.com
tc0001  tomcat7.2  quest.example.com
tc0001  tomcat7.5  www.example.com

Tutaj:

  • -F"/|="ustawia separator pola wejściowego na jeden /lub =. Następnie ustawia separator pola wyjściowego na tabulator.

  • -vOFS='\t'używa -vflagi do ustawiania zmiennej. OFSjest zmienną domyślną dla Separatora pól wyjściowych i jest ustawiony na znak tabulacji. Flaga jest konieczna, ponieważ nie ma wbudowanego dla OFS jak -F.

  • {print $3, $5, $NF} drukuje 3., 5. i ostatnie pole na podstawie separatora pól wejściowych.


Zobacz inny przykład:

$ cat file
hello#how_are_you
i#am_very#well_thank#you

Ten plik ma dwa separatory pól #i _. Jeśli chcemy wydrukować drugie pole niezależnie od tego, czy separator jest jednym, czy drugim, niech oba będą separatorami!

$ awk -F"#|_" '{print $2}' file
how
am

Gdzie pliki są ponumerowane w następujący sposób:

hello#how_are_you           i#am_very#well_thank#you
^^^^^ ^^^ ^^^ ^^^           ^ ^^ ^^^^ ^^^^ ^^^^^ ^^^
  1    2   3   4            1  2   3    4    5    6
fedorqui „SO przestań szkodzić”
źródło
1
Dzięki @BUFU za edycję. Usunąłem odniesienie do OFS, aby skupić się tylko na części FS, ale dobrze jest też to mieć. Twoje zdrowie!
fedorqui „SO przestań krzywdzić”
5

Jeśli biała spacja jest spójna, możesz użyć jej jako separatora, a także zamiast \tbezpośredniego wstawiania , możesz ustawić separator wyjściowy i zostanie on dołączony automatycznie:

< file awk -v OFS='\t' -v FS='[/ ]' '{print $3, $5, $NF}'
Thor
źródło
3

Dla separatora pól dowolnej liczby 2przez 5lub listownie alub #lub miejsca, w którym znak oddzielający należy powtórzyć co najmniej 2 razy i nie więcej niż 6 razy, na przykład:

awk -F'[2-5a# ]{2,6}' ...

Jestem pewien, że istnieją odmiany tego przy użyciu () i parametrów

genom
źródło
3

Perl One-Liner:

perl -F'/[\/=]/' -lane 'print "$F[2]\t$F[4]\t$F[7]"' file

Używane są następujące opcje wiersza polecenia:

  • -npętla wokół każdej linii pliku wejściowego, wstaw linię do $_zmiennej, nie drukuj automatycznie każdej linii

  • -l usuwa nowe linie przed przetwarzaniem i dodaje je z powrotem

  • -atryb autosplit - perl automatycznie podzieli linie wejściowe na @Ftablicę. Domyślnie podział na białe znaki

  • -Fmodyfikator autosplit, w tym przykładzie dzieli się na jeden /lub=

  • -e wykonaj kod perla

Perl jest ściśle związany z awk, jednak @Ftablica autosplit zaczyna się od indeksu, $F[0]a pola awk zaczynają się od 1 $.

Chris Koknat
źródło
2

Innym jest użycie opcji -F, ale przekazanie wyrażenia regularnego w celu wydrukowania tekstu między lewym i prawym nawiasiem ().

Zawartość pliku:

528(smbw)
529(smbt)
530(smbn)
10115(smbs)

Komenda:

awk -F"[()]" '{print $2}' filename

wynik:

smbw
smbt
smbn
smbs

Za pomocą awk wystarczy wydrukować tekst pomiędzy []:

Użyj, awk -F'[][]' ale awk -F'[[]]'nie zadziała.

http://stanlo45.blogspot.com/2020/06/awk-multiple-field-separators.html

Stan Lovisa
źródło
Twoja odpowiedź pojawiła się w kolejce usuwania, ponieważ 9 razy na 10 użytkownicy z 1 reputacją prowadzącą do własnego bloga to zazwyczaj spam. Ale twój jest wyjątkiem od reguły. Ostatnie 10 lat treści to kopalnia złota, mam nadzieję, że masz plan, aby ją uwiecznić.
Eric Leschinski
0

Widzę wiele doskonałych odpowiedzi na tablicy, ale nadal chciałbym przesłać mój kawałek kodu,

awk -F"/" '{print $3 " " $5 " " $7}' sam | sed 's/ cat.* =//g'

Sadhun
źródło
2
print $3 " " $5 " " $7można wydrukować tak jak print $3, $5, $7. Poza tym nie widzę korzyści z używania awk, a następnie pipowania do sed. Ogólnie rzecz biorąc, awk może wystarczyć, a inne odpowiedzi to pokazują.
fedorqui „SO przestań krzywdzić”