Polecenie, które wypisze wartość tylko raz, chociaż pojawia się wiele razy

8

Mam duży plik txt, w którym wartości powtarzają się wiele razy. Czy jest jakieś polecenie, którego mogę użyć, które przejdzie przez plik i jeśli jedna wartość pojawi się raz, nie powtarzaj jej ponownie?

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

Powinien więc wyglądać mniej więcej tak:

S04   
HOH  
CL   
BME 

Chodzi o to, że mam ogromną liczbę różnych wartości, więc nie mogę tego zrobić ręcznie, jak tutaj.

djordje
źródło

Odpowiedzi:

11

Możesz użyć polecenia sortz opcją --unique:

sort -u input-file

Jeśli chcesz zapisać wynik do PLIKU zamiast standardowego wyjścia, użyj opcji --output=FILE:

sort -u input-file -o output-file

Polecenie uniqmożna również zastosować. W tym przypadku identyczne linie muszą być konsekwentne, więc dane wejściowe należy posortować wstępnie - dzięki @RonJohn za notatkę:

sort input-file | uniq > output-file

Podoba mi się sortpolecenie dla podobnych przypadków, ze względu na jego prostotę, ale jeśli pracujesz z dużymi tablicami, awkpodejście z odpowiedzi John1024 może być silniejsze. Oto porównanie czasowe między wspomnianymi podejściami zastosowanymi w pliku (na podstawie powyższego przykładu) z prawie 5 milionami linii:

$ 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

Kolejną znaczącą różnicą jest , że wspomniane przez @Ruslan :

sort -uwypisze wynik dopiero po zakończeniu wprowadzania, podczas gdy to awkpolecenie wydrukuje każdą nową linię wyniku w locie (może to być ważniejsze dla wprowadzania potokowego niż pliku).

Oto ilustracja:

wprowadź opis zdjęcia tutaj

W powyższym przykładzie pętla (pokazana poniżej) generuje 500 losowych kombinacji, każda o długości trzech znaków, liter AD. Te kombinacje są przesyłane do awklub sort.

for i in {1..500}; do cat /dev/urandom | tr -dc A-D | head -c 3; echo; done
pa4080
źródło
1
To bardzo proste polecenie! Wielkie dzięki! Wszystkiego najlepszego.
djordje
2
Och, w czasach, kiedy jedno narzędzie zrobiło jedną rzecz i zrobiło to dobrze !! sort input-file | uniq!!!!
RonJohn
15

Jeśli chcesz zachować linie wyjściowe w tej samej kolejności co linie wejściowe, użyj:

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

Jak to działa:

Wykorzystuje tablicę asocjacyjną ado zliczania liczby wyświetleń każdej linii. Jeśli nie był wcześniej widziany, linia jest drukowana.

John1024
źródło
2
Jest to bardzo trudne awk, ale sort -ujest to prosty sposób.
Pierre François,
4
@ PierreFrançois, ale sort -ujest to również najwolniejszy sposób :) Zaktualizowałem swoją odpowiedź porównując czas między tymi dwoma podejściami.
pa4080
4
Ponadto sort -uwydrukuje wynik dopiero po zakończeniu wprowadzania, podczas gdy to awkpolecenie wydrukuje każdą nową linię wyniku w locie (może to być ważniejsze w przypadku wprowadzania potokowego niż pliku).
Ruslan
Dzięki za tę notatkę, @Ruslan! Próbowałem to zilustrować w mojej odpowiedzi.
pa4080
Muszę wyznać, że awkrozwiązanie jest bardzo dobre, choć nie tak łatwe do odczytania jak sort.
Pierre François,
1

Możesz użyć GNU datamash tutaj również w następujący sposób i zachowa kolejność linii.

datamash rmdup 1 < infile
αғsнιη
źródło
1
Według time porównania jest to najszybsze rozwiązanie, podane tutaj.
pa4080