Я выработал sed
ответ вскоре после того, как опубликовал этот вопрос; никто еще не использовал, sed
так что вот оно:
sed '$!N;/^\(.*\)\n\1$/d;P;D'
Немного поиграв с более общей проблемой (как насчет удаления строк в наборах из трех? Или четырех или пяти?), Мы получили следующее расширяемое решение:
sed -e ':top' -e '$!{/\n/!{N;b top' -e '};};/^\(.*\)\n\1$/d;P;D' temp
Расширено для удаления тройки строк:
sed -e ':top' -e '$!{/\n.*\n/!{N;b top' -e '};};/^\(.*\)\n\1\n\1$/d;P;D' temp
Или удалить квадраты линий:
sed -e ':top' -e '$!{/\n.*\n.*\n/!{N;b top' -e '};};/^\(.*\)\n\1\n\1\n\1$/d;P;D' temp
sed
обладает дополнительным преимуществом по сравнению с большинством других опций, которое заключается в его способности по-настоящему работать в потоке, при этом не требуется больше памяти, чем фактическое количество строк, проверяемых на наличие дубликатов.
Как отметил cuonglm в комментариях , установка языкового стандарта на C необходима, чтобы избежать сбоев в правильном удалении строк, содержащих многобайтовые символы. Таким образом, приведенные выше команды становятся:
LC_ALL=C sed '$!N;/^\(.*\)\n\1$/d;P;D' temp
LC_ALL=C sed -e ':top' -e '$!{/\n/!{N;b top' -e '};};/^\(.*\)\n\1$/d;P;D' temp
LC_ALL=C sed -e ':top' -e '$!{/\n.*\n/!{N;b top' -e '};};/^\(.*\)\n\1\n\1$/d;P;D' temp
# Etc.
C
, в противном случае в многобайтовой локали недопустимый символ в этой локали приведет к сбою команды.