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.

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

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.


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

1
Według time porównania jest to najszybsze rozwiązanie, podane tutaj.
pa4080
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.