NR ve FNR nedir ve “NR == FNR” ne anlama gelir?


85

Kullanarak dosya karşılaştırmasını öğreniyorum awk.

Aşağıdaki gibi sözdizimi buldum

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

Ben önemi nedir anlayamadık NR==FNRbu? Eğer FNR==NRdenersem, aynı çıktıyı da elde ederim?

Bu tam olarak ne yapıyor?


20
Eğer şaşıracak misiniz a==bve b==aaynı sonucu üretilen?
Ed Morton

5
Bkz Two-file Processingüzerinde backreference.org/2010/02/10/idiomatic-awk
Etan Reisner

Yanıtlar:


93

Awk, FNRmevcut dosyadaki kayıt numarasını (tipik olarak satır numarası) NRve toplam kayıt numarasını ifade eder. Operatör ==iki çevreleyen işlenen eşittir doğru döndürür Bir karşılaştırma, bir.

Bu , her dosyanın ilk satırı için 1'e sıfırlanıp artmaya devam ettiği için koşulun NR==FNRyalnızca ilk dosya için doğru olduğu anlamına gelir .FNRNR

Bu kalıp, genellikle yalnızca ilk dosyada eylemler gerçekleştirmek için kullanılır. nextOnlar sadece ilk dışındaki dosyalar üzerinde çalıştırılır, böylece başka komutlar, atlanır blok araçlarının iç.

Koşul FNR==NR, aynı iki işlenenle karşılaştırır NR==FNR, bu nedenle aynı şekilde davranır.


3
"=" bazen eşitliği test etmek ve bazen bir atama yapmak için kullanılır. Atama için çift eşittir işareti kullanılıyorsa, FNR == NR, NR == FNR'den farklı olurdu. Bu yüzden, bu soru soran gibi awk'a aşina olmayan biri için, aynı olup olmadıklarını sormak mantıklı görünüyor.
Todd Walton

@ToddWalton İyi nokta! Başka bir örnek: a='3x'; if [[ $a == 3* ]]; then echo yes; five her iki tarafını da değiştiremezsiniz ==.
Walter A

@WalterA evet, bu doğru (en azından Bash'de). Cevabıma herhangi bir iyileştirme öneriyor musunuz?
Tom Fenech

1
Hayır, cevabınız iyi. Topluluğun cevaplarımızı da aynı derecede beğendiğini görmeyi gerçekten seviyorum. Farklı stiller kullanıyoruz ve her ikisi de çok yardımcı oluyor. Az önce size olumlu oy verdim, bu yüzden şu an için aynı sayıda olumlu oyumuz var.
Walter

72

Dosya2'de aynı zamanda 1. dosyada bulunan anahtarları (satırın ilk kelimesi) arayın.
Adım 1: a dizisini 1. dosyanın ilk sözcükleriyle doldurun:

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

Adım 2: A dizisini doldurun ve aynı komutta dosya 2'yi yok sayın. Bunun için şimdiye kadarki toplam kayıt sayısını mevcut girdi dosyasının numarasıyla kontrol edin.

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

3. Adım: }1. dosya ayrıştırılırken ortaya çıkabilecek eylemleri yok sayın

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

Adım 4: a dizisinde bulunduğunda dosya2 anahtarını yazdırın

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

4
Bu tek astarın harika bir şekilde kaldırılması. Adım 1'deki noktalı virgül gerekli mi?
Tomasz Gandor

2
@TomaszGandor Adım 1'de noktalı virgül gerekli değildir. Adım 3'te ;nextekleyebilirdim , ancak garip bir ekleme ( nextadım 3'te noktalı virgül eklemek ve buna ihtiyaç duymak gibi ). 1. adımı ile test edebilirsiniz awk '{a[$1]} END { for (k in a) { print "a[k]=" k } }' file1.
Walter A

45

Yukarı bak NRve FNRawk kılavuzunda ve ardından durum ne kendinize sorun altında NR==FNRaşağıdaki örnekte:

$ 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

işlenmekte olan dosyanın numarasını da yazdırmak mümkün mü? bunun için yerleşik bir değişken var mı? (Bunun için bir değişken oluşturabileceğimizi ve NR bir olduğunda onu
artırabileceğimizi biliyorum

GNU awk'de bu değişken ARGIND, aksi takdirde yapabilirsiniz FNR==1{ print ++file_nr }.
Ed Morton

Mümkünse, bir soruyu başka bir soruyla cevaplamak o kadar verimli değil;)
Florian Castelain

Soru sormadım, OPs sorusunun cevabını nasıl alacağımı gösterdim.
Ed Morton

20

Yerleşik awkdeğişkenler vardır.

NR - İşlenen toplam kayıt sayısını verir.

FNR - Her girdi dosyası için toplam kayıt sayısını verir.


15

A.txt ve b.txt dosyalarınız olduğunu varsayarsak

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

NR ve FNR'nin awk yerleşik değişkenler olduğunu unutmayın. NR - İşlenen toplam kayıt sayısını verir. (bu durumda hem a.txt hem de b.txt'de) FNR - Her girdi dosyası için toplam kayıt sayısını verir (a.txt veya b.txt'deki kayıtlar)

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

NR == FNR ile ilk eşleşmeyi atlamak için "sonraki" ekleyelim

b.txt ve a.txt içinde

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

b.txt'de ama a.txt'de değil

 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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.