Awk kullanarak önce son satırı işle


11

awkSon veri noktasına göre kullanarak normalleştirmek istediğim bir veri dosyası var . Bu nedenle, önce veriyi normalleştirmek, sonra normal şekilde işlemek için son veri noktasına erişmek istiyorum.

Aşağıdaki yöntem, taciki kez kullanarak işi yapar, ancak belki de gerekenden daha karmaşıktır.

$ cat file
0 5
1 2
2 3
3 4
$ tac file | awk 'NR==1{norm=$2} {print $1, $2/norm}' | tac
0 1.25
1 0.5
2 0.75
3 1

Sorum şu: Sadece awk kullanarak yukarıdaki sonucu elde etmek mümkün mü?

Bence cevap "Hayır, awk dosyayı satır satır tarar", ancak alternatifler için önerilere açığım.

Yanıtlar:


5

Awk olarak iki geçişli bir çözüm olarak yapabilirsiniz:

awk 'FNR == NR { n = $2; next } { print $1, $2/n }' infile infile

Awk sürümünüz ENDFILE bloğunu destekliyorsa (örn. GNU awk 4+), bunu şu şekilde yapabilirsiniz:

awk 'ENDFILE { n = $2 } FNR != NR { print $1, $2/n }' infile infile

Not o kadar daha verimli olduğunu seekilk gördüğü dosya sonuna CAMH cevabı .

açıklama

İlk örnek öncekini hatırlayarak çalışır $2, yani yalnızca yerel satır sayacı ( FNR) genel satır sayacına ( NR) eşit olduğunda değerlendirilir . nextKomut, sonraki satıra atlar bu durumda ikinci argüman ayrıştırılır zaman son bloğu yalnızca değerlendirilir olmasını sağlar.

İkinci örnek benzer bir mantığa sahiptir, ancak bir giriş dosyasının sonuna ulaşıldığında değerlendirilen ENDFILE bloğundan yararlanır.


İlk örnek iyi çalışıyor, ikincisi çalışmıyor $ awk --version GNU Awk 3.1.8. İki girdi dosyasının nasıl işlendiğine ve ne işe yaradığına dair çok küçük bir açıklama ekleyebilir misiniz next?
Bernhard

1
Bernhard: bakınız düzenleme
Thor

6

Veri kaynağınız birden çok kez okunabilen bir dosyaysa (yani bir akış değil), önce tail(1)son satırdan istediğiniz verileri almak ve dosyayı sıralı olarak işlemesi için awk'ye iletmek için kullanmalısınız. taildosyadan önce tüm verileri okumaya gerek kalmadan son satırı okumaya çalışacaktır.

awk -v norm=$(tail -n 1 file | cut -d' ' -f2) '{print $1, $2/norm}' file

Bu, tüm dosyanın arabellek önbelleğine sığmayacağı büyük dosyalarda büyük bir kazanç olacaktır (yani her geçişte bir kez diskten iki kez okunması gerekir) ve taramaya gerek kalmadan daha küçük bir ölçüde yardımcı olacaktır. Son satıra ulaşmak için girdi. Daha küçük dosyalar iki geçişli bir yaklaşımda çok fazla farklılık göstermeyebilir.


3

Bunları bir diziye yükleyebilir ve geriye doğru okuyabilirsiniz:

awk '{x[i++]=$0} END{for (j=i-1; j>=0;) print x[j--] }'

Daha verimli bir şekilde yapabilirsiniz, ancak bu tür bunun neden awkdoğru araç olmadığını gösterir . tacKullanılabilir olan yerlerde kullanmaya devam edin , GNU tac genellikle bu iş için çeşitli araçlardan en hızlısıdır.


Katılıyorum, bir- fordöngüler kullanmak awkçözüm değildir.
Bernhard
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.