Questo one-liner rimuove le righe duplicate dall'input di testo senza preordinare.
Ad esempio:
$ cat >f
q
w
e
w
r
$ awk '!a[$0]++' <f
q
w
e
r
$
Il codice originale che ho trovato su internet diceva:
awk '!_[$0]++'
Questo è stato ancora più sconcertante per me quando ho preso _
avere un significato speciale in awk, come in Perl, ma si è rivelato essere solo il nome di un array.
Ora, capisco la logica dietro l'one-liner:
ogni riga di input viene utilizzata come chiave in un array hash, quindi, al termine, l'hash contiene righe univoche nell'ordine di arrivo.
Quello che vorrei imparare è come esattamente questa notazione viene interpretata da awk. Per esempio. che segno di botto (!
) significa e gli altri elementi di questo frammento di codice.
Come funziona?
Risposta accettata:
Ecco una risposta "intuitiva", per una spiegazione più approfondita del meccanismo di awk vedi @Cuonglm's
In questo caso, !a[$0]++
, il post-incremento ++
può essere messo da parte per un momento, non cambia il valore dell'espressione. Quindi, guarda solo !a[$0]
. Qui:
a[$0]
utilizza la riga corrente $0
come chiave dell'array a
, prendendo il valore ivi memorizzato. Se questa chiave particolare non è mai stata referenziata prima, a[$0]
restituisce la stringa vuota.
!a[$0]
Il !
nega il valore di prima. Se era vuoto o zero (falso), ora abbiamo un risultato vero. Se era diverso da zero (vero), abbiamo un risultato falso. Se l'intera espressione è stata valutata come true, significa che a[$0]
non è stato impostato per iniziare, l'intera riga viene stampata come azione predefinita.
Inoltre, indipendentemente dal vecchio valore, l'operatore di post-incremento ne aggiunge uno a a[$0]
, quindi la prossima volta che si accede allo stesso valore nell'array, sarà positivo e l'intera condizione avrà esito negativo.