2013-08-19 12 views
5

Ciao sto cercando un awk che può trovare due pattern e stampare i dati tra di loro a un file solo se nel mezzo c'è un terzo pattern nel mezzo. per esempio:Awk tra due pattern con pattern nel mezzo

Start 
1 
2 
middle 
3 
End 
Start 
1 
2 
End 

And the output will be: 
Start 
1 
2 
middle 
3 
End 

ho trovato nel web awk '/ patterns1 /,/Pattern2 /' percorso> text.txt ma ho bisogno solo di uscita con la terza modelli nel mezzo.

+0

Adatta, ma fattibile. Avrai bisogno di salvare il materiale tra Inizio e Fine, e quando incontri Medio, nota che il materiale salvato deve essere stampato, e mentre elabori Fine, controlla se il materiale salvato deve essere stampato. Non ho il tempo di ridurlo al codice ora. (Salva ogni '$ 0' in un array dopo aver riconosciuto Start, interrompi il salvataggio in Fine, stampando l'array se appropriato e cancellando l'array a prescindere.) –

+0

Inoltre, possono esserci righe di dati non tra Inizio e Fine? Oppure è sempre una sequenza di linee Start..End, ma solo alcune devono essere stampate. –

+0

può essere vuoto, ma ne esiste solo uno con schema centrale –

risposta

2

Questo awk dovrebbe funzionare:

awk '$1=="Start"{ok++} ok>0{a[b++]=$0} $1=="middle"{ok++} $1=="End"{if(ok>1) for(i=0; i<length(a); i++) print a[i]; ok=0;b=0;delete a}' file 

Start 
1 
2 
middle 
3 
End 

Expanded:

awk '$1 == "Start" { 
    ok++ 
} 
ok > 0 { 
    a[b++] = $0 
} 
$1 == "middle" { 
    ok++ 
} 
$1 == "End" { 
    if (ok > 1) 
     for (i=0; i<length(a); i++) 
     print a[i]; 
    ok=0; 
    b=0; 
    delete a 
}' file 
3

Basta utilizzare alcune bandiere con awk:

/Start/ { 
    start_flag=1 
} 

/middle/ { 
    mid_flag=1 
} 

start_flag { 
    n=NR; 
    lines[NR]=$0 
} 

/End/ { 
    if (start_flag && mid_flag) 
     for(i=n;i<NR;i++) 
      print lines[i] 
    start_flag=mid_flag=0 
    delete lines 
} 
3

E qui è una soluzione senza bandiere:

$ awk 'BEGIN{RS="End"}/middle/{printf "%s", $0; print RT}' file 
Start 
1 
2 
middle 
3 
End 

Spiegazione: La variabile RS è il separatore disco, quindi abbiamo impostato su "Fine", in modo che ogni record è separato da "End".

Poi filtrare i record che contengono "di mezzo", con il filtro /middle/, e per i record corrispondenti della stampa il record corrente con $0 e il separatore con print RT

+0

Interessante ... ma penso che meriti qualche spiegazione su come funziona. –

+1

Questo non tiene conto di 'Start', ma stampa solo i record che contengono sia' middle' che 'End'. Stai aggiungendo anche una nuova riga aggiuntiva dopo la registrazione. –

+0

@JonathanLeffler ha aggiunto una spiegazione – user000001

3

Modificato l'awk user000001

awk '/middle/{printf "%s%s\n",$0,RT}' RS="End" file 

EDIT: prova Aggiunto su Start per tag

awk '/Start/ && /middle/{printf "%s%s\n",$0,RT}' RS="End" file 
+0

Questo non controlla 'Inizio' – mschilli

+0

Aggiornato il mio post per testare' Inizio' – Jotne

2

Ciò wor k con qualsiasi awk moderna:

awk '/Start/{f=1;rec=""} f{rec=rec $0 ORS} /End/{if (rec~/middle/) printf "%s",rec}' file 

Le soluzioni che stabiliscono RS a "End" sono specifici per gawk, che può andare bene ma è sicuramente degno di nota.