Comment puis-je traiter des enregistrements multilignes avec awk dans un script bash?

13

example.txt est ci-dessous

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

Im utilisant le script bash et disons que je veux rechercher un restaurant par son nom dans le fichier ci-dessus. Demandez à l'utilisateur de saisir le nom du restaurant et il devrait imprimer les informations concernant ce restaurant (5 lignes).

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

Je sais que la ligne de code ci-dessus imprimera la ligne entière qui correspond au modèle "McDonalds" et "KFC" mais cela imprimera simplement la 1ère ligne du fichier texte mais pas le reste des informations sur ce restaurant. Comment puis-je lui dire d'imprimer toutes les informations (5 lignes) à partir de la seule entrée utilisateur du nom du restaurant?

Selena Gomez
la source

Réponses:

11

Avec awk, vous pouvez changer le séparateur d' enregistrement . Par défaut, il s'agit d'une nouvelle ligne, donc chaque ligne du fichier est un enregistrement. Si vous définissez la RSvariable sur la chaîne vide, awk considérera les enregistrements comme séparés par des lignes vides:

awk -v name="KFC" -v RS="" '$0 ~ "Restaurant: " name' example.txt
glenn jackman
la source
Je ne comprends pas ta question. C'est assez vague. Est-ce l'affectation ou l'utilisation que vous n'obtenez pas?
glenn jackman
3

En utilisant 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

Explication

Il s'agit d'une sedfonction de base , vous pouvez consulter des SCRIPTS D'UNE LIGNE UTILES POUR SED

# print section of file between two regular expressions (inclusive)
sed -n '/Iowa/,/Montana/p'             # case sensitive
BMW
la source
Ajoutez l'explication.
BMW
Mais pourquoi la modification suggérée a-t-elle été rejetée? Je n'ai pas changé la réponse. Je viens d'améliorer la mise en forme.
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

La commande ci-dessus récupérera et imprimera les 4 lignes consécutives avec la ligne actuelle car elle a été introduite dans une boucle for. Le modèle de recherche $2=="KFC"aidera à obtenir une ligne particulière à partir de plusieurs lignes.

Avinash Raj
la source
0

Une autre solution possible:

awk 'BEGIN{FS="\n";RS="\n\n"}{if($1=="KFC")print $0}' example.txt
Faisal
la source
Le {if($1=="KFC")print $0}peut être condensé à juste $1 == "KFC", car l'action par défaut pour une vraie condition est d'imprimer l'enregistrement.
muru
0

Il suffit d'imprimer à partir de la ligne contenant le nom que vous voulez, jusqu'à la dernière ligne contenant le mot Phone(en supposant bien sûr que toutes les entrées suivent le même modèle et auront toujours Phonecomme enregistrement de fin)

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

Si nous voulions compliquer un peu les choses, nous pourrions imprimer exactement 5 lignes après le match, comme ceci:

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

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

La stopvariable ne sera pas définie, donc NR<=stopn'imprimera rien, jusqu'à ce /McDonalds/{stop=NR+5;}qu'une partie définisse réellement la variable, et cela ne se produira que lorsque nous trouverons la correspondance.

Sergiy Kolodyazhnyy
la source