Comando che stamperà il valore una sola volta sebbene appaia più volte


8

Ho un grande file txt in cui i valori si ripetono più volte. C'è qualche comando che posso usare che passerà attraverso il file e se appare un valore una volta non ripeterlo di nuovo?

SO4
HOH
CL
BME
HOH
SO4
HOH
CL
BME
HOH
SO4
HOH
SO4
HOH
CL
BME
HOH
SO4
HOH
CL
BME
HOH
CL

Quindi dovrebbe assomigliare a questo:

S04   
HOH  
CL   
BME 

Il fatto è che ho un numero enorme di valori diversi, quindi non posso farlo manualmente come qui.

Risposte:


11

È possibile utilizzare il comando sortcon l'opzione --unique:

sort -u input-file

Se si desidera scrivere il risultato su FILE anziché sull'output standard, utilizzare l'opzione --output=FILE:

sort -u input-file -o output-file

Il comando uniqpotrebbe anche essere applicato. In questo caso le linee identiche devono essere consequenziali, quindi l'input deve essere ordinato preliminare - grazie a @RonJohn per questa nota:

sort input-file | uniq > output-file

Mi piace il sortcomando per casi simili, per la sua semplicità, ma se lavori con array di grandi dimensioni l' awkapproccio della risposta di John1024 potrebbe essere più potente. Ecco un confronto temporale tra gli approcci citati, applicato su un file (basato sull'esempio sopra) con quasi 5 milioni di righe:

$ cat input-file | wc -l
20000000

$ TIMEFORMAT=%R
$ time sort -u input-file | wc -l
64
7.495

$ time sort input-file | uniq | wc -l
64
7.703

$ time awk '!a[$0]++' input-file | wc -l      # from John1024's answer
64
1.271

$ time datamash rmdup 1 < input-file | wc -l  # from αғsнιη's answer
64
0.770

Un'altra differenza significativa è quella menzionata da @Ruslan :

sort -ustamperà il risultato solo quando l'input è terminato, mentre questo awkcomando stampa al volo ogni nuova linea di risultato (questo può essere più importante per l'input con piping rispetto al file).

Ecco un'illustrazione:

inserisci qui la descrizione dell'immagine

Nell'esempio sopra, il loop (mostrato sotto) genera 500 combinazioni casuali, ciascuna con una lunghezza di tre caratteri, delle lettere AD. Queste combinazioni vengono reindirizzate a awko sort.

for i in {1..500}; do cat /dev/urandom | tr -dc A-D | head -c 3; echo; done

1
È un comando molto semplice! Grazie molto! Ti auguro il meglio.
Djordje,

2
Oh, per i giorni in cui una utility ha fatto una cosa e l'ha fatta bene !! sort input-file | uniq!!!!
RonJohn

15

Se si desidera mantenere le righe di output nello stesso ordine delle righe di input, utilizzare:

$ awk '!a[$0]++' file
SO4
HOH
CL
BME

Come funziona:

Questo utilizza un array associativo aper contare il numero di volte in cui ogni riga è stata vista in precedenza. Se non è stato visto in precedenza, la linea viene stampata.


2
È molto complicato awk, ma sort -uè il modo più semplice.
Pierre François,

4
@ PierreFrançois, ma sort -uè anche il modo più lento :) Ho aggiornato la mia risposta con un confronto temporale tra i due approcci.
pa4080,

4
Inoltre, sort -ustamperà il risultato solo dopo che l'input è terminato, mentre questo awkcomando stampa al volo ogni nuova riga di risultato (questo potrebbe essere più importante per l'input del pip che per il file).
Ruslan,

Grazie per questa nota, @Ruslan! Ho cercato di illustrarlo nella mia risposta.
pa4080,

Devo confessare che la awksoluzione è ottima, anche se non così facile da leggere sort.
Pierre François

1

Puoi usare GNU datamash anche qui come segue e manterrà l'ordine delle righe.

datamash rmdup 1 < infile

1
Secondo il time confronto questa è la soluzione più veloce, fornita qui.
pa4080,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.