Как я могу удалить повторяющиеся строки в файле в Unix? - PullRequest
112 голосов
/ 18 сентября 2009

Есть ли способ удалить дубликаты строк в файле в Unix?

Я могу сделать это с помощью команд sort -u и uniq, но я хочу использовать sed или awk. Это возможно?

Ответы [ 8 ]

244 голосов
/ 18 сентября 2009
awk '!seen[$0]++' file.txt

seen - это ассоциативный массив, в который Awk будет передавать каждую строку файла. Если строка отсутствует в массиве, seen[$0] будет иметь значение false. ! является логическим оператором NOT и будет инвертировать ложь в истину. Awk напечатает строки, где выражение оценивается как true. ++ увеличивает seen так, что seen[$0] == 1 после первого поиска строки, а затем seen[$0] == 2 и т. Д.
Awk оценивает все, кроме 0 и "" (пустая строка), в true. Если дублирующая строка помещается в seen, тогда !seen[$0] будет иметь значение false и строка не будет записана в вывод.

27 голосов
/ 18 сентября 2009

С http://sed.sourceforge.net/sed1line.txt: (Пожалуйста, не спрашивайте меня, как это работает ;-))

 # delete duplicate, consecutive lines from a file (emulates "uniq").
 # First line in a set of duplicate lines is kept, rest are deleted.
 sed '$!N; /^\(.*\)\n\1$/!P; D'

 # delete duplicate, nonconsecutive lines from a file. Beware not to
 # overflow the buffer size of the hold space, or else use GNU sed.
 sed -n 'G; s/\n/&&/; /^\([ -~]*\n\).*\n\1/d; s/\n//; h; P'
12 голосов
/ 11 сентября 2015

Однострочный Perl, аналогичный решению awk @ jonas:

perl -ne 'print if ! $x{$_}++' file

Этот вариант удаляет завершающие пробелы перед сравнением:

perl -lne 's/\s*$//; print if ! $x{$_}++' file

Этот вариант редактирует файл на месте:

perl -i -ne 'print if ! $x{$_}++' file

Этот вариант редактирует файл на месте и создает резервную копию file.bak

perl -i.bak -ne 'print if ! $x{$_}++' file
7 голосов
/ 05 ноября 2010

Однострочник, который Андре Миллер опубликовал выше, работает, за исключением последних версий sed, когда входной файл заканчивается пустой строкой и без символов. На моем Mac мой процессор просто вращается.

Бесконечный цикл, если последняя строка пуста и не содержит символов :

sed '$!N; /^\(.*\)\n\1$/!P; D'

Не зависает, но вы теряете последнюю строку

sed '$d;N; /^\(.*\)\n\1$/!P; D'

Объяснение в самом конце sed FAQ :

Специалист по GNU sed считает, что, несмотря на проблемы с переносимостью
это может привести к изменению команды N на печать (вместо
удалить) пространство шаблона более соответствовало интуиции
о том, как команда «добавить следующую строку» должна вести себя.
Другим фактом, способствующим изменению, было то, что "{N; команда;}" будет
удалить последнюю строку, если файл имеет нечетное количество строк, но
выведите последнюю строку, если файл имеет четное количество строк.

Для преобразования скриптов, которые использовали прежнее поведение N (удаление
пространство шаблона при достижении EOF) для сценариев, совместимых с
все версии sed, меняют одинокое "N;" в «$ d; N;» .

4 голосов
/ 04 сентября 2013

Альтернативный способ использования Vim (Vi-совместимый) :

Удалить повторяющиеся последовательные строки из файла:

vim -esu NONE +'g/\v^(.*)\n\1$/d' +wq

Удалить дубликаты, непоследовательные и непустые строки из файла:

vim -esu NONE +'g/\v^(.+)$\_.{-}^\1$/d' +wq

3 голосов
/ 05 июня 2017

Первое решение также от http://sed.sourceforge.net/sed1line.txt

$ echo -e '1\n2\n2\n3\n3\n3\n4\n4\n4\n4\n5' |sed -nr '$!N;/^(.*)\n\1$/!P;D'
1
2
3
4
5

основная идея:

print ONLY once of each duplicate consecutive lines at its LAST appearance and use D command to implement LOOP.

Объясняет:

  1. $!N;: если текущая строка НЕ ​​является последней строкой, используйте команду N, чтобы прочитать следующую строку в pattern space.
  2. /^(.*)\n\1$/!P: если содержимое текущего pattern space - это два duplicate string, разделенных \n, что означает, что следующая строка - это same с текущей строкой, мы НЕ можем печатать ее в соответствии с нашей основной идеей ; в противном случае, что означает, что текущая строка является последним видом всех ее повторяющихся последовательных строк, теперь мы можем использовать команду P для печати символов в текущем pattern space util \n (\n также напечатано).
  3. D: мы используем команду D для удаления символов в текущем pattern space util \n (\n также удалено), затем содержимое pattern space является следующей строкой.
  4. и D заставит sed перейти к ее команде FIRST $!N, но НЕ прочтет следующую строку из файла или стандартного потока ввода.

Второе решение легко понять (от себя):

$ echo -e '1\n2\n2\n3\n3\n3\n4\n4\n4\n4\n5' |sed -nr 'p;:loop;$!N;s/^(.*)\n\1$/\1/;tloop;D'
1
2
3
4
5

Основная идея:

print ONLY once of each duplicate consecutive lines at its FIRST appearance and use : command & t command to implement LOOP.

Объясняет:

  1. прочитать новую строку из входного потока или файла и распечатать ее один раз.
  2. использовать :loop набор команд a label с именем loop.
  3. используйте N, чтобы прочитать следующую строку в pattern space.
  4. используйте s/^(.*)\n\1$/\1/ для удаления текущей строки, если следующая строка совпадает с текущей строкой, мы используем команду s для выполнения действия delete.
  5. если команда s выполнена успешно, используйте команду tloop force sed для перехода к label с именем loop, который будет выполнять тот же цикл для следующих строк, если нет дубликатов последовательные линии линии latest printed; в противном случае используйте команду D для delete строки, которая совпадает с latest-printed line, и заставьте sed перейти к первой команде, которая является командой p, содержимое текущего pattern space равно следующая новая строка.
0 голосов
/ 15 августа 2018

Это может быть достигнуто с помощью awk
Внизу строки будут отображаться уникальные значения

awk file_name | uniq

Вы можете вывести эти уникальные значения в новый файл

awk file_name | uniq > uniq_file_name

новый файл uniq_file_name будет содержать только уникальные значения, без дубликатов

0 голосов
/ 18 июня 2014
cat filename | sort | uniq -c | awk -F" " '$1<2 {print $2}'

Удаляет дубликаты строк с помощью awk.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...