Comando che stamperà il valore solo una volta sebbene appaia molte volte

8

Ho un grande file txt in cui i valori si ripetono molte volte. C'è qualche comando che posso usare che passerà attraverso il file e se un valore appare 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.

    
posta djordje 06.01.2018 - 09:26

3 risposte

11

Potresti usare il comando sort con l'opzione --unique :

sort -u input-file

Se vuoi scrivere il risultato su FILE anziché sullo standard output, usa l'opzione --output=FILE :

sort -u input-file -o output-file

Potrebbe essere applicato anche il comando uniq . In questo caso le linee identiche devono essere consequenziali, quindi l'input deve essere ordinato preliminarmente - grazie a @RonJohn per this note:

sort input-file | uniq > output-file

Mi piace il comando sort per casi simili, a causa della sua semplicità, ma se lavori con array di grandi dimensioni l'approccio awk da John1024's risposta potrebbe essere più potente. Ecco un confronto temporale tra gli approcci menzionati, applicato su un file (basato sull'esempio precedente) 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 è che menzionato da @Ruslan :

% Bl0ck_qu0te%

Ecco un'illustrazione:

Nell'esempio sopra, il loop (mostrato sotto) genera 500 combinazioni casuali, ciascuna con una lunghezza di tre caratteri, delle lettere A-D. Queste combinazioni sono collegate a awk o sort .

for i in {1..500}; do cat /dev/urandom | tr -dc A-D | head -c 3; echo; done
    
risposta data pa4080 06.01.2018 - 09:35
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 l'array associativo a per contare il numero di volte in cui ogni linea è stata vista in precedenza. Se non è stato visto in precedenza, la linea viene stampata.

    
risposta data John1024 06.01.2018 - 09:36
1

Puoi utilizzare GNU datamash anche qui di seguito e manterrai l'ordine delle righe.

datamash rmdup 1 < infile
    
risposta data αғsнιη 27.03.2018 - 20:05

Leggi altre domande sui tag