2012-10-30 13 views
5

Sto tentando di utilizzare awk per analizzare un'espressione multilinea. Uno di questi è il seguente:corrispondenza awk e multilinea (sub-regex)

_begin hello world ! 
_attrib0 123 
_attrib1 super duper 
_attrib1 yet another value 
_attrib2 foo 
_end 

Ho bisogno di estrarre il valore associato a _begin e _attrib1. Quindi, in questo esempio, lo script awk dovrebbe restituire (uno per riga):

hello world ! super duper yet another value 

Il separatore utilizzato è un carattere di tabulazione (\ t). Gli spazi sono usati solo all'interno di stringhe.

risposta

8

Il seguente script awk fa il lavoro:

#!/usr/bin/awk -f 
BEGIN { FS="\t"; } 
/^_begin/  { output=$2; } 
$1=="_attrib1" { output=output " " $2; } 
/^_end/  { print output; } 

Non ha specificato se si desidera una scheda (\t) per essere il vostro uscita separatore campo. Se lo fai, fammelo sapere e aggiornerò la risposta. (Oppure si può, è banale.)

Naturalmente, se si desidera una spaventosa alternativo (in quanto ci stiamo avvicinando a Hallowe'en), ecco una soluzione che utilizza sed:

$ sed -ne '/^_begin./{s///;h;};/^_attrib1[^0-9]/{s///;H;x;s/\n/ /;x;};/^_end/{;g;p;}' input.txt 
hello world ! super duper yet another value 

Come funziona questo lavoro? Mwaahahaa, sono contento che tu abbia chiesto.

  • /^_begin./{s///;h;}; - Quando vediamo _begin, spoglia e memorizzare il resto della linea di sed "hold buffer".
  • /^_attrib1[^0-9]/{s///;H;x;s/\n/ /;x;}; - Quando vediamo _attrib1, toglierlo, aggiungerlo al buffer di attesa, scambiare il buffer di attesa e lo spazio del motivo, sostituire le nuove righe con spazi e scambiare nuovamente il buffer di attesa e lo spazio del motivo.
  • /^_end/{;g;p;} - Siamo arrivati ​​alla fine, quindi estrai il buffer di mantenimento nello spazio del motivo e stampalo.

Ciò presuppone che il separatore del campo di input sia solo una singola scheda.

COSÌ semplice. Chi ha mai detto che lo sed era arcano ?!

+0

_attrib11 sta facendo questo script per fallisce (_attrib1 corrisponde) – malat

+0

Non c'era '_attrib11' nei dati di esempio che hai fornito. Se vuoi, puoi creare condizioni come '$ 1 ==" _ attrib1 "' invece di '/^_ attrib1 /' per gestirle, oppure puoi lasciarle come espressioni regolari ma terminarle, come '$ 1 ~/^ _ attrib1 $/'. Raccomando la prima soluzione alternativa; scegli sempre prima la corrispondenza delle stringhe, regex (almeno) la seconda. – ghoti

+0

Aggiornato la mia risposta per il tuo nuovo requisito. Aggiunta anche un'alternativa "sed", per il tuo piacere di lettura. – ghoti

1

Questo dovrebbe funzionare:

#!/bin/bash 

awk 'BEGIN {FS="\t"} {if ($1=="_begin" || $1=="_attrib1") { output=output " " $2 }} END{print output}'