Wie kann ich mehrzeilige Datensätze mit awk in einem Bash-Skript verarbeiten?

13

example.txt ist unten

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

Ich benutze ein Bash-Skript und lass uns sagen, ich möchte nach einem Restaurant anhand seines Namens aus der obigen Datei suchen. Bitten Sie den Benutzer, den Namen des Restaurants einzugeben, und er sollte die Informationen zu diesem Restaurant ausdrucken (5 Zeilen).

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

Ich weiß, dass in der obigen Codezeile die gesamte Zeile gedruckt wird, die mit den Mustern "McDonalds" und "KFC" übereinstimmt, aber nur die erste Zeile aus der Textdatei, aber nicht die restlichen Informationen zu diesem Restaurant. Wie kann ich festlegen, dass alle Informationen (5 Zeilen) nur durch die Benutzereingabe des Restaurantnamens gedruckt werden sollen?

Selena Gomez
quelle

Antworten:

11

Mit awk können Sie das Datensatztrennzeichen ändern . Standardmäßig handelt es sich um eine neue Zeile, sodass jede Zeile der Datei ein Datensatz ist. Wenn Sie die RSVariable auf die leere Zeichenfolge setzen, betrachtet awk Datensätze als durch Leerzeilen getrennt:

awk -v name="KFC" -v RS="" '$0 ~ "Restaurant: " name' example.txt
Glenn Jackman
quelle
Ich verstehe deine Frage nicht. Es ist ziemlich vage. Ist es die Aufgabe oder die Verwendung, die Sie nicht bekommen?
Glenn Jackman
3

Verwenden von 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

Erläuterung

Dies ist eine grundlegende sedFunktion, Sie beziehen WISSENS ONE-LINE - Skripte für SED

# print section of file between two regular expressions (inclusive)
sed -n '/Iowa/,/Montana/p'             # case sensitive
BMW
quelle
Fügen Sie die Erklärung hinzu.
BMW
Aber warum wurde die vorgeschlagene Änderung abgelehnt? Ich habe die Antwort nicht geändert. Ich habe gerade die Formatierung verbessert.
Daisy
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

Mit dem obigen Befehl werden die aufeinanderfolgenden 4 Zeilen zusammen mit der aktuellen Zeile abgerufen und gedruckt, da sie in eine for-Schleife eingegeben wurden. Das Suchmuster $2=="KFC"hilft dabei, eine bestimmte Zeile aus den mehreren Zeilen zu ermitteln.

Avinash Raj
quelle
0

Eine andere mögliche Lösung:

awk 'BEGIN{FS="\n";RS="\n\n"}{if($1=="KFC")print $0}' example.txt
Faisal
quelle
Die {if($1=="KFC")print $0}kann auf nur verdichtet werden $1 == "KFC", da die Standardaktion für eine wahre Bedingung das Drucken des Datensatzes ist.
Muru
0

Es ist ausreichend, von der Zeile mit dem gewünschten Namen bis zur letzten Zeile mit dem Wort zu drucken Phone(vorausgesetzt natürlich, dass alle Einträge dem gleichen Muster folgen und immer den Abschlussdatensatz haben Phone).

$> 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

Wenn wir es etwas komplizieren wollten, könnten wir genau 5 Zeilen nach dem Match drucken, wie folgt:

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

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

Die stopVariable wird nicht gesetzt, es NR<=stopwird also nichts gedruckt, bis der /McDonalds/{stop=NR+5;}Teil die Variable tatsächlich setzt, und das wird nur passieren, wenn wir die Übereinstimmung finden.

Sergiy Kolodyazhnyy
quelle