Команда, которая будет печатать значение только один раз, хотя она появляется много раз

8

У меня есть большой текстовый файл, в котором значения повторяются много раз. Есть ли какая-нибудь команда, которую я могу использовать, которая будет проходить через файл, и если одно значение появится один раз, не повторять его снова?

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

Так это должно выглядеть примерно так:

S04   
HOH  
CL   
BME 

Дело в том, что у меня огромное количество разных значений, поэтому я не могу сделать это вручную, как здесь.

Джордже
источник

Ответы:

11

Вы можете использовать команду sortс опцией --unique:

sort -u input-file

Если вы хотите записать результат в FILE вместо стандартного вывода, используйте опцию --output=FILE:

sort -u input-file -o output-file

Команда uniqтакже может быть применена. В этом случае идентичные строки должны быть последовательными, поэтому входные данные должны быть предварительно отсортированы - спасибо @RonJohn за эту заметку:

sort input-file | uniq > output-file

Мне нравится sortкоманда для подобных случаев из-за ее простоты, но если вы работаете с большими массивами, awkподход из ответа John1024 может быть более мощным. Вот сравнение времени между упомянутыми подходами, примененными к файлу (на основе приведенного выше примера) с почти 5 миллионами строк:

$ 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

Другое существенное отличие заключается в том, что упомянуто @Ruslan :

sort -uбудет печатать результат только после завершения ввода, в то время как эта awkкоманда будет печатать каждую новую строку результатов на лету (это может быть важнее для ввода по каналу, чем для файла).

Вот иллюстрация:

введите описание изображения здесь

В приведенном выше примере цикл (показан ниже) генерирует 500 случайных комбинаций, каждая из которых имеет длину три символа, из букв AD. Эти комбинации передаются по трубопроводу awkили sort.

for i in {1..500}; do cat /dev/urandom | tr -dc A-D | head -c 3; echo; done
pa4080
источник
1
Это очень простая команда! Большое спасибо! Всего наилучшего.
Джордже
2
О, за те дни, когда одна утилита делала одну вещь и делала это хорошо !! sort input-file | uniq!!!!
RonJohn
15

Если вы хотите сохранить выходные строки в том же порядке, что и входные строки, используйте:

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

Как это работает:

При этом используется ассоциативный массив aдля подсчета количества раз, которое каждая строка была видна ранее. Если это не было замечено ранее, строка печатается.

John1024
источник
2
Это очень сложно awk, но sort -uэто простой способ.
Пьер Франсуа
4
@ PierreFrançois, но sort -uтакже самый медленный способ :) Я обновил свой ответ сравнением времени между двумя подходами.
pa4080
4
Кроме того, sort -uбудет печатать результат только после завершения ввода, в то время как эта awkкоманда будет печатать каждую новую строку результатов на лету (это может быть более важно для ввода по каналу, чем для файла).
Руслан
Спасибо за эту заметку, @Ruslan! Я попытался проиллюстрировать это в своем ответе.
pa4080
Я должен признаться, что awkрешение очень хорошее, хотя и не так легко читается, как sort.
Пьер Франсуа
1

Здесь вы также можете использовать GNU datamash следующим образом и сохранить порядок строк.

datamash rmdup 1 < infile
αғsнιη
источник
1
Согласно time сравнению это самое быстрое решение, представленное здесь.
pa4080