2015-09-09 2 views
28

Ich lerne Dateivergleich mit awk.Was ist "NR == FNR" in awk?

fand ich Syntax wie unten,

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

Ich konnte nicht verstehen, welche Bedeutung der NR==FNR in ist das? Wenn ich mit FNR==NR versuche, dann bekomme ich auch die gleiche Ausgabe?

Was genau macht es?

+8

Wären Sie überrascht, wenn 'a == b' und' b == a' ergaben das gleiche Ergebnis? –

+3

Siehe "Zwei-Datei-Verarbeitung" auf http://backreference.org/2010/02/10/idiomatic-awk/ –

Antwort

8

Es gibt awk eingebaute Variablen.

NR - Gibt die Gesamtzahl der verarbeiteten Datensätze an.

FNR - Gibt die Gesamtzahl der Datensätze für jede Eingabedatei an.

32

In awk bezieht sich FNR auf die Datensatznummer (normalerweise die Zeilennummer) in der aktuellen Datei und NR bezieht sich auf die gesamte Datensatznummer. Dies bedeutet, dass die Bedingung NR==FNR nur für die erste Datei gilt, da FNR für die erste Zeile jeder Datei wieder auf 1 zurückgesetzt wird, aber NR weiterhin zunimmt.

Dieses Muster wird normalerweise verwendet, um Aktionen nur für die erste Datei auszuführen. Die next innerhalb des Blocks bedeutet, dass alle weiteren Befehle übersprungen werden, so dass sie nur für andere als die ersten Dateien ausgeführt werden.

Es ist unklar, warum Sie erwarten würden, dass FNR==NR sich von NR==FNR unterscheidet.

22

Schauen NR und FNR in dem awk Handbuch und dann fragen Sie sich, was die Bedingung, unter denen NR==FNR im folgende Beispiel:

$ 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

Geben Sie für Tasten (erstes Wort Linie) in file2, die auch sind in Datei1.
Schritt 1: Anordnung A mit den ersten Worten von 1-Datei füllen:

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

Schritt 2: Anordnung einer Füllung und Datei 2 in dem gleichen Befehl ignorieren. Prüfen Sie dazu die Gesamtzahl der bisherigen Datensätze mit der Nummer der aktuellen Eingabedatei.

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

Schritt 3: Ignorieren Aktionen, die nach } kommen könnten, wenn die Datei 1

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

Schritt 4 Parsen: Drucktaste von file2, wenn Sie in dem Feld gefunden ein

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

danke für diesen – nktokyo

+0

Brilliant Takedown dieser Einliner. Ist das Semikolon in Schritt 1 notwendig? –

+0

@TomaszGandor Das Semikolon wird in Schritt 1 nicht benötigt. Ich hätte es in Schritt 3 hinzufügen können, aber '; next' ist eine seltsame Addition (ich möchte' next' hinzufügen und benötige das Semikolon in Schritt 3). Sie können Schritt 1 mit 'awk '{a [$ 1]} END {für (k in a) {print" a [k] = "k}}' Datei1 'testen. –

1

Unter der Annahme, have Dateien a.txt und b.txt mit

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

Denken Sie daran, NR und FNR sind awk eingebaute Variablen. NR - Gibt die Gesamtzahl der verarbeiteten Datensätze an. (in diesem Fall sowohl in a.txt als auch in b.txt) FNR - Gibt die Gesamtanzahl der Datensätze für jede Eingabedatei (Datensätze in entweder a.txt oder 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 

läßt In "next" die ersten mit NR angepassten überspringen == FNR

in b.txt und 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 aber nicht 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 
Verwandte Themen