Есть ли способ удалить дубликаты строк в файле в Unix?
Я могу сделать это с помощью команд sort -u и uniq, но я хочу использовать sed или awk.
Это возможно?
Есть ли способ удалить дубликаты строк в файле в Unix?
Я могу сделать это с помощью команд sort -u и uniq, но я хочу использовать sed или awk.
Это возможно?
awk '!seen[$0]++' file.txt
 seen является ассоциативным массивом, который Awk передает каждой строке файла. Если строка не находится в массиве, то seen[$0] будет оцениваться как false. ! является логическим оператором NOT и инвертирует значение false в true. Awk напечатает строки, в которых выражение будет равно true. ++ увеличивает seen так, что seen[$0] == 1 после первого появления строки, а затем seen[$0] == 2 и т.д. 
Awk оценивает все, кроме 0 и "" (пустая строка), для true. Если повторяющаяся строка помещается в seen, то !seen[$0] будет оцениваться как false, и строка не будет записана на выход.
От 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'
Perl one-liner похож на решение @jonas awk:
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
Однострочный шрифт, описанный Андре Миллером выше, за исключением последних версий sed, когда входной файл заканчивается пустой строкой и без символов. На моем Mac мой процессор просто вращается.
Бесконечный цикл, если последняя строка пуста и не имеет символов:
 sed '$!N; /^\(.*\)\n\1$/!P; D'
Не зависает, но вы теряете последнюю строку
 sed '$d;N; /^\(.*\)\n\1$/!P; D'
Объяснение находится в самом конце часто задаваемых вопросов:
Сторонник GNU sed счел, что, несмотря на проблемы с переносимостью это приведет к изменению команды N для печати (а не delete) пространство шаблонов было более согласовано с одной интуицией
о том, как должна вести себя команда "добавить следующую строку".
Другим фактом, благоприятным для изменения, было то, что "{N; command;}" будет удалите последнюю строку, если файл имеет нечетное число строк, но
напечатайте последнюю строку, если файл имеет четное количество строк.Чтобы преобразовать скрипты, которые использовали прежнее поведение N (удаление пространство шаблонов при достижении EOF) для скриптов, совместимых с все версии sed, изменить одиночный "N"; до "$ d; N;" .
Альтернативный способ использования Vim (Vi-совместимый):
Удалить повторяющиеся, последовательные строки из файла:
 vim -esu NONE +'g/\v^(.*)\n\1$/d' +wq
Удалить из файла дубликаты, несоответствия и непустые строки:
 vim -esu NONE +'g/\v^(.+)$\_.{-}^\1$/d' +wq
$ 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.
Объясняет:
$!N;: если текущая строка НЕ является последней строкой, используйте команду N, чтобы прочитать следующую строку в pattern space./^(.*)\n\1$/!P: если содержимое текущего pattern space равно двум duplicate string, разделенным на \n, что означает, что следующая строка - это same с текущей строкой, мы НЕ можем ее распечатать в соответствии с нашей основной идеей; в противном случае это означает, что текущая строка представляет собой ПОСЛЕДНЕЕ появление всех повторяющихся последовательных строк, теперь мы можем использовать команду P для печати символов в текущем pattern space util \n (\n также напечатано).D: мы используем команду D для удаления символов в текущем pattern space util \n (\n также удаляется), тогда содержимое pattern space является следующей строкой.
Команда 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.
Объясняет:
:loop набор команд a label с именем loop.N для чтения следующей строки в pattern space.s/^(.*)\n\1$/\1/ для удаления текущей строки, если следующая строка совпадает с текущей строкой, мы используем команду s для выполнения действия delete.s выполнена успешно, используйте команду tloop command force sed, чтобы перейти к label с именем loop, которая будет делать тот же цикл для следующих строк, если нет дубликатов последовательные линии линии, которая latest printed; в противном случае используйте команду D для delete строки, которая совпадает с линией latest-printed line, а force sed - перейти к первой команде, которая является командой P, содержимое текущего pattern space - следующая новая строка.Это может быть достигнуто с помощью awk
Внизу строки будут отображаться уникальные значения
awk file_name | uniq
Вы можете вывести эти уникальные значения в новый файл
awk file_name | uniq > uniq_file_name
новый файл uniq_file_name будет содержать только уникальные значения, без дубликатов
cat filename | sort | uniq -c | awk -F" " '$1<2 {print $2}'
Удаляет повторяющиеся строки с помощью awk.