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


8

У мене великий файл txt, у якому значення повторюються багато разів. Чи є якась команда, яку я можу використовувати, яка буде проходити через файл, і якщо одне значення з'являється один раз, не повторюйте його знову?

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

1
Це дуже проста команда! Дуже дякую! Все найкраще.
djordje

2
О, за дні, коли одна утиліта зробила одне і зробила це добре !! sort input-file | uniq!!!!
RonJohn

15

Якщо ви хочете зберегти вихідні рядки в тому ж порядку, що і рядки введення, використовуйте:

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

Як це працює:

При цьому використовується асоціативний масив aдля підрахунку кількості попередніх переглядів кожного рядка. Якщо вона раніше не була помічена, рядок друкується.


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

1
Відповідно до time порівняння, це найшвидше рішення, яке надається тут.
pa4080
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.