Cette ligne unique supprime les lignes en double de l'input de text sans pré-sorting.
Par exemple:
$ cat >f q w e w r $ awk '!a[$0]++' <f q w e r $
Le code original que j'ai trouvé sur les internets se lit comme suit:
awk '!_[$0]++'
C'était encore plus perplexe pour moi car j'ai pris _
pour avoir un sens spécial dans awk, comme dans Perl, mais il s'est avéré être juste un nom d'un tableau.
Maintenant, je comprends la logique derrière le one-liner: chaque ligne d'input est utilisée comme key dans un tableau de hachage, ainsi, à la fin, le hachage contient des lignes uniques dans l'ordre d'arrivée.
Ce que je voudrais apprendre, c'est comment exactement cette notation est interprétée par awk. Par exemple ce que le signe bang ( !
) Signifie et les autres éléments de cet extrait de code.
Comment ça marche?
Voyons voir,
!a[$0]++
premier
a[$0]
nous regardons la valeur d' a[$0]
(tableau a
avec ligne d'input entière ( $0
) comme key).
S'il n'existe pas ( !
Est la négation dans le test sera eval à vrai)
!a[$0]
nous imprimons la ligne d'input $0
(action par défaut).
En outre, nous ajoutons un ( ++
) à a[$0]
, donc la prochaine fois !a[$0]
sera évalué à false.
Nice, trouvez !! Vous devriez jeter un oeil au code golf!
Voici le traitement:
a[$0]
: regarde la valeur de la key $0
, dans le tableau associatif a
. S'il n'existe pas, créez-le.
a[$0]++
: incrémente la valeur d' a[$0]
, renvoie l'ancienne valeur comme valeur de l'expression. Si a[$0]
n'existe pas, renvoyez 0
et incrémentez a[$0]
à 1
(l'opérateur ++
returnne la valeur numérique).
!a[$0]++
: annule la valeur de l'expression. Si a[$0]++
renvoie 0
, l'expression entière est évaluée à true, make awk
exécuté l'action par défaut print $0
. Sinon, l'expression entière est évaluée à false, ce qui fait que awk
ne fait rien.
Les references:
Avec gawk
, nous pouvons utiliser dgawk (ou awk --debug
avec une version plus récente) pour déboguer un script gawk
. Tout d'abord, créez un script gawk
, nommé test.awk
:
BEGIN { a = 0; !a++; }
Puis exécutez:
dgawk -f test.awk
ou:
gawk --debug -f test.awk
Dans la console du débogueur:
$ 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>
Vous pouvez voir, Op_postincrement
été exécuté avant Op_not
.
Vous pouvez également utiliser si
ou stepi
au lieu de s
ou step
pour voir plus clairement:
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++;