Awk '! A [$ 0] ++' nasıl çalışır?


39

Bu tek astar, ön sıralama yapmadan yinelenen satırları metin girişinden kaldırır.

Örneğin:

$ cat >f
q
w
e
w
r
$ awk '!a[$0]++' <f
q
w
e
r
$ 

İnternette bulduğum orijinal kod okundu:

awk '!_[$0]++'

_Perl'de olduğu gibi awk'de özel bir anlam kazandığım için bu daha da şaşırtıcıydı , ama sadece bir dizinin adıydı.

Şimdi, bir astarın arkasındaki mantığı anlıyorum: her giriş satırı bir karma dizisinde anahtar olarak kullanılır, böylece tamamlandıktan sonra karma, varış sırasına göre benzersiz çizgiler içerir.

Öğrenmek istediğim şey, bu gösterimin awk tarafından tam olarak nasıl yorumlandığı. Örneğin, bang işareti ( !) ve bu kod snippet'in diğer elemanları.

O nasıl çalışır?


başlık yanıltıcı, $ o (o) değil, 0 $ (Sıfır) olmalıdır.
Archemar

2
Bir karma olduğu için, sırasız olduğundan, "varış sırasına göre" aslında doğru değil.
Kevin,

Yanıtlar:


35

Bakalım,

 !a[$0]++

ilk

 a[$0]

değerine bakarız a[$0]( abütün giriş satırını içeren dizi ( $0) anahtar olarak).

Eğer yoksa ( !testte olumsuzluk doğru olarak değerlendirilecektir)

 !a[$0]

giriş satırını yazdırıyoruz $0(varsayılan eylem).

Ayrıca, bir tane ( ++) ekliyoruz a[$0], böylece bir dahaki sefere !a[$0]false olarak değerlendireceğiz.

Güzel, bul !! Golf koduna bir göz atmalısın!


1
Yani özü şudur: tek tırnak işaretleri içindeki ifade awkher girdi satırı için bir test olarak kullanılır ; Testin başarılı olduğu her zaman, awkeylemi, ihmal edildiğinde, küme parantezleri içinde gerçekleştirir {print}. Teşekkürler!
Alexander Shcheblikin

3
@Archemar: Bu cevap yanlış, benimkine bakın.
cuonglm

@AlexanderShcheblikin içinde awk, varsayılan işlemdir {print $0}. Bu, doğru olarak değerlendirilen herhangi bir şeyin bunu varsayılan olarak yürüteceği anlamına gelir. Yani, örneğin awk '1' file, tüm hatları yazdırır awk '$1' fileolan ilk alan boş değilse veya 0, vb tüm bu satırları yazdıran
fedorqui

6
@Gnouc Bu cevapta ciddi bir hata görmüyorum. Bahsettiğiniz şey buysa, artırma gerçekten ifadenin değeri hesaplandıktan sonra uygulanır. Artımın baskıdan önce gerçekleştiği doğrudur, ancak bu temel açıklamayı etkilemeyen küçük bir hassasiyettir.
Gilles 'SO- kötülük' dur

1
Yeni başlayanlar için en iyi açıklamayı burada anlamak için buldum: qr.ae/TUIVxM
GP92

29

İşte işleme:

  • a[$0]: $0ilişkisel dizideki anahtarın değerine bakınız a. Eğer yoksa, oluşturun.

  • a[$0]++: değerini artırır, a[$0]eski değeri ifade değeri olarak döndürür. Eğer a[$0], mevcut geri dönmez 0ve artış a[$0]için 1( ++operatör getiri sayısal değer).

  • !a[$0]++: ifadenin değerini olumsuzlar. a[$0]++Dönüş olursa 0, tüm ifade doğru olarak değerlendirilir, awkvarsayılan eylemi gerçekleştirir print $0. Aksi takdirde, tüm ifade yanlış olarak değerlendirilir, nedenler awkhiçbir şey yapmaz.

Referanslar:

İle bir betiği hata ayıklamak gawkiçin dgawk (veya awk --debugdaha yeni bir sürümle) kullanabiliriz gawk. İlk önce, gawkadında bir script oluşturun test.awk:

BEGIN {                                                                         
    a = 0;                                                                      
    !a++;                                                                       
}

O zaman koş:

dgawk -f test.awk

veya:

gawk --debug -f test.awk

Hata ayıklayıcı konsolunda:

$ dgawk -f test.awk
dgawk> trace on
dgawk> watch a
Watchpoint 1: a
dgawk> run
Starting program: 
[     1:0x7fe59154cfe0] Op_rule             : [in_rule = BEGIN] [source_file = test.awk]
[     2:0x7fe59154bf80] Op_push_i           : 0 [PERM|NUMCUR|NUMBER]
[     2:0x7fe59154bf20] Op_store_var        : a [do_reference = FALSE]
[     3:0x7fe59154bf60] Op_push_lhs         : a [do_reference = TRUE]
Stopping in BEGIN ...
Watchpoint 1: a
  Old value: untyped variable
  New value: 0
main() at `test.awk':3
3           !a++;
dgawk> step
[     3:0x7fe59154bfc0] Op_postincrement    : 
[     3:0x7fe59154bf40] Op_not              : 
Watchpoint 1: a
  Old value: 0
  New value: 1
main() at `test.awk':3
3           !a++;
dgawk>

Gördün mü, Op_postincrementdaha önce idam edildi Op_not.

Ayrıca kullanabilir siveya stepiyerine sya stepdaha net görmek için:

dgawk> si
[     3:0x7ff061ac1fc0] Op_postincrement    : 
3           !a++;
dgawk> si
[     3:0x7ff061ac1f40] Op_not              : 
Watchpoint 1: a
  Old value: 0
  New value: 1
main() at `test.awk':3
3           !a++;

3
@Archemar: Cevabınız bunun !daha önce uygulandığını gösteriyor ++.
cuonglm

6
Bu cevap yanlış. Artım, !operatörün sonucu hesaplandıktan sonra gerçekleşir . Operatör önceliği ile (benzer !a[$0]++şekilde ayrıştırılır !(a[$0]++)) değerlendirme sırasını karıştırırsınız ( a[$0]ifadenin değeri hesaplandıktan sonra gerçekleşen yeni değerin atanması ).
Gilles 'SO- kötülük' dur

5
@Gnouc Alıntı yaptığınız geçitte doğru yazıyor ve açıkladığınız şekilde çalıştıysa, bu kod istenen etkiye sahip olmaz. İlk önce değer !xhesaplanır, xeski değer nerede a[$0]. Sonra a[$0]ayarlanır 1+x.
Gilles 'SO- kötülük' dur

7
Awk’ın yaptığı şeyin analizinin doğru olduğuna inanıyorum. Dün başka türlü ima ettiğim için özür dilerim. Ancak, Archemar'ın cevabını eleştirmeniz yanlış. Archemar önceliği yanlış anlamıyor, sen de öncelik sırasını değerlendirme sırasına karıştırıyorsun (önceki yorumuma bakınız). Archemar'ın cevabından herhangi bir sözünü çıkarırsanız, cevabınız doğru olmalıdır. Olduğu gibi, Archemar'ın yanlış olduğunu kanıtlamaya odaklanmış ve bu böyle değil.
Gilles 'SO- kötü olmak'

5
iyi, en azından şimdi
awk'ın
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.