2015-09-09 12 views
28

Sto imparando il paragone dei file usando awk.Che cosa è "NR == FNR" in awk?

ho trovato la sintassi come qui di seguito,

awk 'NR==FNR{a[$1];next}$1 in a{print $1}' file1 file2 

Non riuscivo a capire che cosa è significato di NR==FNR in questo? Se provo con FNR==NR, anch'io ottengo lo stesso risultato?

Che cosa fa esattamente?

+8

Sareste sorpresi se 'a == b' e' b == a' hanno prodotto lo stesso risultato? –

+3

Vedere 'Elaborazione a due file 'su http://backreference.org/2010/02/10/idiomatic-awk/ –

risposta

8

Esistono variabili integrate awk.

NR - Fornisce il numero totale di record elaborati.

FNR - Fornisce il numero totale di record per ciascun file di input.

32

In awk, FNR si riferisce al numero di record (in genere il numero di riga) nel file corrente e NR si riferisce al numero di record totale. Ciò significa che la condizione NR==FNR è vera solo per il primo file, poiché FNR si reimposta su 1 per la prima riga di ciascun file, ma lo standard NR continua ad aumentare.

Questo modello viene in genere utilizzato per eseguire azioni solo sul primo file. Il next all'interno del blocco significa che tutti gli altri comandi vengono saltati, quindi vengono eseguiti solo su file diversi dal primo.

Non è chiaro il motivo per cui ci si aspetta FNR==NR ad essere diversa a NR==FNR.

22

Look up NR e FNR nel manuale awk e poi chiedetevi che cosa è la condizione in cui NR==FNR nel seguente esempio:

$ cat file1 
a 
b 
c 

$ cat file2 
d 
e 

$ awk '{print FILENAME, NR, FNR, $0}' file1 file2 
file1 1 1 a 
file1 2 2 b 
file1 3 3 c 
file2 4 1 d 
file2 5 2 e 
34

Cercare chiavi (prima parola della riga) in file2 che sono anche in file1.
Fase 1: riempire serie A con le prime parole del file di 1:

awk '{a[$1];}' file1 

Fase 2: Riempire gamma di file e 2 nello stesso comando ignorare. Per questo controlla il numero totale di record fino ad ora con il numero del file di input corrente.

awk 'NR==FNR{a[$1]}' file1 file2 

Fase 3: Ignorare le azioni che potrebbero venire dopo } durante l'analisi di file 1

awk 'NR==FNR{a[$1];next}' file1 file2 

Fase 4: tasto di stampa di file2 quando ha trovato nella matrice un

awk 'NR==FNR{a[$1];next} $1 in a{print $1}' file1 file2 
+0

grazie per questo – nktokyo

+0

takedown brillante di questo one-liner. È necessario il punto e virgola nel passaggio 1? –

+0

@TomaszGandor Il punto e virgola non è necessario nel passaggio 1. Avrei potuto aggiungerlo nel passaggio 3, ma '; next' è un'aggiunta strana (come aggiungere' next' e serve il punto e virgola nel passaggio 3). Puoi testare il passaggio 1 con 'awk '{a [$ 1]} END {per (k in a) {print" a [k] = "k}}' file1'. –

1

si Assumendo avere file a.txt e b.txt con

cat a.txt 
a 
b 
c 
d 
1 
3 
5 
cat b.txt 
a 
1 
2 
6 
7 

Tenere presente NR e FNR sono variabili integrate di awk. NR - Fornisce il numero totale di record elaborati. (in questo caso sia in a.txt che in b.txt) FNR - Indica il numero totale di record per ogni file di input (record in entrambe le a.txt o b.txt)

awk 'NR==FNR{a[$0];}{if($0 in a)print FILENAME " " NR " " FNR " " $0}' a.txt b.txt 
a.txt 1 1 a 
a.txt 2 2 b 
a.txt 3 3 c 
a.txt 4 4 d 
a.txt 5 5 1 
a.txt 6 6 3 
a.txt 7 7 5 
b.txt 8 1 a 
b.txt 9 2 1 

aggiungiamo "Avanti" per saltare il primo abbinato con NR == FNR

in b.txt e in a.txt

awk 'NR==FNR{a[$0];next}{if($0 in a)print FILENAME " " NR " " FNR " " $0}' a.txt b.txt 
b.txt 8 1 a 
b.txt 9 2 1 

in b.txt ma non in a.txt

awk 'NR==FNR{a[$0];next}{if(!($0 in a))print FILENAME " " NR " " FNR " " $0}' a.txt b.txt 
b.txt 10 3 2 
b.txt 11 4 6 
b.txt 12 5 7 

awk 'NR==FNR{a[$0];next}!($0 in a)' a.txt b.txt 
2 
6 
7