Jak mogę przetwarzać rekordy wieloliniowe za pomocą awk w skrypcie bash?

14

example.txt jest poniżej

Restaurant: McDonalds 
City: Miami
State: Florida
Address: 123 Biscayne Blvd
Phone: 911

Restaurant: 5 guys
City: Atlanta
State: Georgia
Address: 123 Peachtree Rd
Phone: 911

Restaurant: KFC
City: NYC
State: NY
Address: 123 Madison Square
Phone: 911

Używam skryptu bash i powiedzmy, że chcę wyszukać restaurację według jej nazwy z powyższego pliku. Poproś użytkownika o podanie nazwy restauracji, a powinna wydrukować informacje dotyczące tej restauracji (5 wierszy).

awk '/McDonalds/> /KFC/' example.txt

Wiem, że powyższy wiersz kodu wydrukuje całą linię pasującą do wzorca „McDonalds” i „KFC”, ale to po prostu wydrukuje pierwszy wiersz z pliku tekstowego, ale nie resztę informacji o tej restauracji. Jak mogę nakazać wydrukowanie wszystkich informacji (5 linii) z samego wpisu nazwy restauracji?

Selena Gomez
źródło

Odpowiedzi:

11

Za pomocą awk możesz zmienić separator rekordów . Domyślnie jest to nowa linia, więc każda linia pliku jest rekordem. Jeśli ustawisz RSzmienną na pusty ciąg znaków, awk rozważy rekordy jako oddzielone pustymi wierszami:

awk -v name="KFC" -v RS="" '$0 ~ "Restaurant: " name' example.txt
Glenn Jackman
źródło
Nie rozumiem twojego pytania. To jest dość niejasne. Czy to zadanie, którego nie używasz?
glenn jackman
3

Używanie sed:

$ sed -n '/KFC/,/^$/p' file
Restaurant: KFC
City: NYC
State: NY
Address: 123 Madison Square
Phone: 911

$ sed -n '/McDo/,/^$/p' file
Restaurant: McDonalds
City: Miami
State: Florida
Address: 123 Biscayne Blvd
Phone: 911

Wyjaśnienie

Jest to podstawowa sedfunkcja, możesz odnieść PRZYDATNE SKRZYDŁA W JEDNEJ LINII DO SED

# print section of file between two regular expressions (inclusive)
sed -n '/Iowa/,/Montana/p'             # case sensitive
BMW
źródło
Dodaj wyjaśnienie.
BMW
Ale dlaczego sugerowana edycja została odrzucona? Nie zmieniłem odpowiedzi. Właśnie poprawiłem formatowanie.
stokrotka
2
$ awk '$2=="KFC" {print; for(i=1; i<=4; i++) { getline; print}}' example.txt

Restaurant: KFC
City: NYC
State: NY
Address: 123 Madison Square
Phone: 911

Powyższe polecenie pobierze i wydrukuje kolejne 4 linie wraz z bieżącą linią, ponieważ zostało wprowadzone do pętli for. Wzorzec wyszukiwania $2=="KFC"pomoże uzyskać konkretną linię z wielu linii.

Avinash Raj
źródło
0

Inne możliwe rozwiązanie:

awk 'BEGIN{FS="\n";RS="\n\n"}{if($1=="KFC")print $0}' example.txt
Faisal
źródło
{if($1=="KFC")print $0}Można kondensować się po prostu $1 == "KFC", ponieważ domyślna akcja dla prawdziwego stanu jest, aby wydrukować zapis.
mur 12.04.16
0

Wystarczy wydrukować z wiersza zawierającego żądaną nazwę, aż do ostatniego wiersza zawierającego słowo Phone(zakładając oczywiście, że wszystkie wpisy mają ten sam wzór i zawsze będą miały Phonezapis kończący)

$> awk '/5 guys/,/Phone/' restaurants.txt                                     
Restaurant: 5 guys
City: Atlanta
State: Georgia
Address: 123 Peachtree Rd
Phone: 911
$> awk '/McDonalds/,/Phone/' restaurants.txt                                  
Restaurant: McDonalds 
City: Miami
State: Florida
Address: 123 Biscayne Blvd
Phone: 911

Gdybyśmy chcieli trochę to skomplikować, moglibyśmy wydrukować dokładnie 5 linii po meczu, w ten sposób:

awk '/McDonalds/{stop=NR+5}; NR<=stop ' restaurants.txt                    

Restaurant: McDonalds 
City: Miami
State: Florida
Address: 123 Biscayne Blvd
Phone: 911

stopZmienna nie zostanie ustawiona, więc NR<=stopnie będzie niczego drukować, aż /McDonalds/{stop=NR+5;}część faktycznie ustawia zmienną, a to nastąpi tylko wtedy, gdy znajdziemy mecz.

Sergiy Kolodyazhnyy
źródło