Удаление повторяющихся строк в vi?


124

У меня есть текстовый файл, содержащий длинный список записей (по одной в каждой строке). Некоторые из них являются дубликатами, и я хотел бы знать, можно ли (и если да, то как) удалить любые дубликаты. Мне интересно сделать это из vi / vim, если это возможно.



4
Этому 1 год; это 10 месяцев. Итак, наоборот.
Сидиус,

Консенсус @Sydius теперь заключается в том, чтобы установить приоритет подсчета голосов (которого у вас также больше): meta.stackexchange.com/questions/147643/… И это не дубликаты, в нем не упоминается Vim :-)
Сиро Сантилли 郝海东 冠状 病六四 事件 法轮功 08

Ответы:


271

Если вы согласны с сортировкой файла, вы можете использовать:

:sort u

6
Это так красиво. Спасибо!
Shrayas

8
Если сортировка недопустима, используйте, :%!uniqчтобы просто удалить повторяющиеся записи без сортировки файла.
cryptic0 06

как только вы используете команду, весь файл изменяется? как ты вернешься? Я уже по ошибке сохранил файл ... мой плохой
nilon

Просто используйте команду отмены Vim :u
adampasz

25

Попробуй это:

:%s/^\(.*\)\(\n\1\)\+$/\1/

Он ищет любую строку, за которой сразу следует одна или несколько собственных копий, и заменяет ее одной копией.

Сделайте копию своего файла, прежде чем попробовать. Это не проверено.


1
@hop Спасибо за тестирование. В то время у меня не было доступа к vim.
Шон,

2
это выделяет все повторяющиеся строки для меня, но не удаляет, я пропустил шаг здесь?
ak85

Я уверен, что это также выделит строку, за которой следует строка с таким же префиксом, но более длинная.
hippietrail

3
Единственная проблема с этим заключается в том, что если у вас есть несколько дубликатов (3 или более одинаковых строк), вам придется запускать это много раз, пока все дубли не исчезнут, поскольку это удаляет только один набор дубликатов за раз.
horta

2
Еще один недостаток: это не сработает, если ваши повторяющиеся строки уже находятся рядом друг с другом. Сортировка в первую очередь будет одним из способов убедиться, что они рядом друг с другом. В этом случае другие ответы, вероятно, будут лучше.
Орта

23

Из командной строки просто выполните:

sort file | uniq > file.new

1
Это мне очень пригодилось для огромного файла. Спасибо!
Rafid

1
Не удалось заставить принятый ответ работать, так как :sort uон висел в моем большом файле. Это сработало очень быстро и идеально. Спасибо!
Tgsmith61591

1
'uniq' is not recognized as an internal or external command, operable program or batch file.
hippietrail

1
Да, я пробовал эту технику с файлом размером 2,3 ГБ, и это было потрясающе быстро.
DanM

@hippietrail Вы используете ПК с windows? Может быть, вы можете использовать cygwin.
12431234123412341234123

8

awk '!x[$0]++' yourfile.txtесли вы хотите сохранить порядок (т. е. сортировка недопустима). Чтобы вызвать его из vim, :!можно использовать.


4
Это прекрасно! Отсутствие необходимости в сортировке - это именно то , что я искал!
Cometsong

6
g/^\(.*\)$\n\1/d

У меня работает в Windows. Однако сначала необходимо отсортировать строки.


1
Это приведет к удалению строки, следующей за строкой, которая является его префиксом: с aaaaпоследующим ошибочным aaaabbудалением aaaa.
hippietrail

5

Я бы совмещал два из приведенных выше ответов:

go to head of file
sort the whole file
remove duplicate entries with uniq

1G
!Gsort
1G
!Guniq

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


1
'uniq' is not recognized as an internal or external command, operable program or batch file.
hippietrail

3

Затем выберите линии в режиме визуальных линий ( Shift+ v) :!uniq. Это будет ловить только дубликаты, которые идут один за другим.


1
Просто чтобы отметить это будет только работать на компьютерах с Uniq программы установлены т.е. Linux, Mac, FreeBSD и т.д.
anteatersa

Это будет лучший ответ для тех, кому не нужна сортировка. А если вы пользователь Windows, попробуйте Cygwin или MSYS.
fx-kirin


0
:%s/^\(.*\)\(\n\1\)\+$/\1/gec

или

:%s/^\(.*\)\(\n\1\)\+$/\1/ge

это мой ответ для вас, он может удалить несколько повторяющихся строк и сохранить только одну!


0

Я бы использовал !}uniq, но это работает, только если нет пустых строк.

Для каждой строки в файле используйте: :1,$!uniq.


0

Эта версия удаляет только повторяющиеся строки, которые совпадают. Я имею в виду, удаляет только последовательные повторяющиеся строки. При использовании данной карты функция не замечает беспорядка с пустыми строками. Но если изменить REGEX, чтобы он соответствовал началу строки, ^он также удалит повторяющиеся пустые строки.

" function to delete duplicate lines
function! DelDuplicatedLines()
    while getline(".") == getline(line(".") - 1)
        exec 'norm! ddk'
    endwhile
    while getline(".") == getline(line(".") + 1)
        exec 'norm! dd'
    endwhile
endfunction
nnoremap <Leader>d :g/./call DelDuplicatedLines()<CR>

0

Альтернативный метод, который не использует vi / vim (для очень больших файлов), - это из командной строки Linux использовать sort и uniq:

sort {file-name} | uniq -u

0

Это сработало для меня как для, так .csvи для.txt

awk '!seen[$0]++' <filename> > <newFileName>

Объяснение: Первая часть команды печатает уникальные строки, а вторая часть, т.е. после средней стрелки, предназначена для сохранения вывода первой части.

awk '!seen[$0]++' <filename>

>

<newFileName>

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.