seen- это ассоциативный массив, в который Awk будет передавать каждую строку файла. Если строки нет в массиве, seen[$0]будет присвоено значение false. Это !логический оператор НЕ, который преобразует ложное в истинное. Awk напечатает строки, в которых выражение оценивается как истинное. В ++приросты seenтак , что seen[$0] == 1после того, как в первый раз строка найдена , а затем seen[$0] == 2, и так далее.
Awk оценивает все, кроме 0и ""(пустая строка), как истина. Если в него помещена повторяющаяся строка, seenтогда !seen[$0]будет вычислено значение false, и строка не будет записана на вывод.
Чтобы сохранить это в файле, мы можем сделать этоawk '!seen[$0]++' merge_all.txt > output.txt
Акаш Кандпал
5
Важное предостережение: если вам нужно сделать это для нескольких файлов, и вы добавляете больше файлов в конце команды или используете подстановочный знак ... массив 'visible' заполнится повторяющимися строками из ВСЕХ файлов. Если вместо этого вы хотите обрабатывать каждый файл независимо, вам нужно сделать что-то вродеfor f in *.txt; do gawk -i inplace '!seen[$0]++' "$f"; done
Nick K9
@ NickK9, который кумулятивно устраняет дублирование нескольких файлов, само по себе потрясающе. Хороший совет
# 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'
! «$ N; /^(.*)\n\1$/!P; D 'означает: «Если вы не на последней строке, прочтите другую строку. Теперь посмотрите, что у вас есть, и если это НЕ материал, за которым следует новая строка, а затем то же самое снова, распечатайте материал. Теперь удалите материал (до новой строки) ".
Бета,
2
'ГРАММ; с / \ п / && /; / ^ ([- ~] * \ n). * \ n \ 1 / d; s / \ п //; час; P 'означает, грубо говоря, «Добавить все пространство удержания к этой строке, затем, если вы видите дублированную строку, выбросите все это, в противном случае скопируйте весь беспорядок обратно в пространство удержания и распечатайте первую часть (это строка, которую вы просто читать »
Beta,
Является $!частью необходимо? Не sed 'N; /^\(.*\)\n\1$/!P; D'то же самое? Я не могу привести пример, в котором они разные на моей машине (fwiw я пробовал пустую строку в конце с обеими версиями, и они обе были в порядке).
eddi
1
Спустя почти 7 лет никто не ответил на @amichair ... <sniff> меня огорчает. ;) В любом случае, [ -~]представляет собой диапазон символов ASCII от 0x20 (пробел) до 0x7E (тильда). Они рассматриваются в печатаемые символы ASCII (связанная страница также 0x7F / удаления , но это не кажется правильным). Это делает решение неработоспособным для тех, кто не использует ASCII, или для тех, кто использует, скажем, символы табуляции. Более переносимый [^\n]включает в себя намного больше символов ... фактически все, кроме одного.
Однострочник, опубликованный Андре Миллером выше, работает, за исключением последних версий sed, когда входной файл заканчивается пустой строкой и без символов. На моем Mac мой процессор просто крутится.
Бесконечный цикл, если последняя строка пуста и не содержит символов :
Сопровождающий GNU sed чувствовал, что, несмотря на проблемы с переносимостью, которые
это может вызвать, изменение команды N на печать (а не
удаление) пространства шаблонов больше соответствовало интуитивным представлениям
о том, как должна себя вести команда для «добавления следующей строки» .
Другой факт, благоприятствующий изменению, заключался в том, что "{N; command;}"
удалит последнюю строку, если в файле нечетное количество строк, но
напечатает последнюю строку, если в файле четное количество строк.
Чтобы преобразовать сценарии, в которых использовалось прежнее поведение N (удаление
пространства шаблонов при достижении EOF), в сценарии, совместимые со
всеми версиями sed, измените одиночный "N;" в "$ d; N;" ,
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утилите \n( \nтакже напечатанной).
D: мы используем Dкоманду для удаления символов в текущей pattern spaceутилите \n( \nтакже удаленной), тогда содержимое pattern spaceследующей строки.
и Dкоманда заставит sedперейти к своей FIRSTкоманде $!N, но НЕ будет читать следующую строку из файла или стандартного входного потока.
print ONLY once of each duplicate consecutive lines at its FIRST appearance and use : command & t command to implement LOOP.
Объясняет:
прочтите новую строку из входного потока или файла и распечатайте ее один раз.
используйте :loopкоманду set a labelnamed loop.
используйте Nдля чтения следующей строки в pattern space.
используйте s/^(.*)\n\1$/\1/для удаления текущей строки, если следующая строка совпадает с текущей строкой, мы используем sкоманду для выполнения deleteдействия.
если sкоманда выполнена успешно, то используйте tloopкоманду force, sedчтобы перейти к labelназванному loop, что сделает тот же цикл для следующих строк, при этом не будет повторяющихся последовательных строк строки, которая есть latest printed; в противном случае используйте Dкоманду для deleteстроки, которая совпадает с latest-printed line, и принудительный sedпереход к первой команде, которая является pкомандой, содержимое текущей pattern spaceявляется следующей новой строкой.
uniq
, достаточно одного.awk
, но это будет довольно ресурсозатратным для больших файлов.Ответы:
seen
- это ассоциативный массив, в который Awk будет передавать каждую строку файла. Если строки нет в массиве,seen[$0]
будет присвоено значение false. Это!
логический оператор НЕ, который преобразует ложное в истинное. Awk напечатает строки, в которых выражение оценивается как истинное. В++
приростыseen
так , чтоseen[$0] == 1
после того, как в первый раз строка найдена , а затемseen[$0] == 2
, и так далее.Awk оценивает все, кроме
0
и""
(пустая строка), как истина. Если в него помещена повторяющаяся строка,seen
тогда!seen[$0]
будет вычислено значение false, и строка не будет записана на вывод.источник
awk '!seen[$0]++' merge_all.txt > output.txt
for f in *.txt; do gawk -i inplace '!seen[$0]++' "$f"; done
Из http://sed.sourceforge.net/sed1line.txt : (Пожалуйста, не спрашивайте меня, как это работает ;-))
источник
$!
частью необходимо? Неsed 'N; /^\(.*\)\n\1$/!P; D'
то же самое? Я не могу привести пример, в котором они разные на моей машине (fwiw я пробовал пустую строку в конце с обеими версиями, и они обе были в порядке).[ -~]
представляет собой диапазон символов ASCII от 0x20 (пробел) до 0x7E (тильда). Они рассматриваются в печатаемые символы ASCII (связанная страница также 0x7F / удаления , но это не кажется правильным). Это делает решение неработоспособным для тех, кто не использует ASCII, или для тех, кто использует, скажем, символы табуляции. Более переносимый[^\n]
включает в себя намного больше символов ... фактически все, кроме одного.Однострочник Perl, аналогичный awk-решению @jonas:
Этот вариант удаляет завершающие пробелы перед сравнением:
Этот вариант редактирует файл на месте:
Этот вариант редактирует файл на месте и делает резервную копию
file.bak
источник
Однострочник, опубликованный Андре Миллером выше, работает, за исключением последних версий sed, когда входной файл заканчивается пустой строкой и без символов. На моем Mac мой процессор просто крутится.
Бесконечный цикл, если последняя строка пуста и не содержит символов :
sed '$!N; /^\(.*\)\n\1$/!P; D'
Не зависает, но вы теряете последнюю строчку
sed '$d;N; /^\(.*\)\n\1$/!P; D'
Объяснение находится в самом конце FAQ по sed :
источник
Альтернативный способ использования Vim (совместимый с Vi) :
Удалите повторяющиеся последовательные строки из файла:
vim -esu NONE +'g/\v^(.*)\n\1$/d' +wq
Удалите повторяющиеся, непоследовательные и непустые строки из файла:
vim -esu NONE +'g/\v^(.+)$\_.{-}^\1$/d' +wq
источник
Первое решение также из http://sed.sourceforge.net/sed1line.txt
основная идея:
Объясняет:
$!N;
: если текущая строка НЕ является последней строкой, используйтеN
команду для чтения следующей строкиpattern space
./^(.*)\n\1$/!P
: если содержимое текущей строки разделеноpattern space
двумяduplicate string
символами\n
, что означает, что следующая строка является строкойsame
с текущей строкой, мы НЕ можем распечатать ее в соответствии с нашей основной идеей; в противном случае, что означает, что текущая строка является ПОСЛЕДНИМ появлением всех повторяющихся последовательных строк, теперь мы можем использоватьP
команду для печати символов в текущейpattern space
утилите\n
(\n
также напечатанной).D
: мы используемD
команду для удаления символов в текущейpattern space
утилите\n
(\n
также удаленной), тогда содержимоеpattern space
следующей строки.D
команда заставитsed
перейти к своейFIRST
команде$!N
, но НЕ будет читать следующую строку из файла или стандартного входного потока.Второе решение легко понять (от себя):
основная идея:
Объясняет:
:loop
команду set alabel
namedloop
.N
для чтения следующей строки вpattern space
.s/^(.*)\n\1$/\1/
для удаления текущей строки, если следующая строка совпадает с текущей строкой, мы используемs
команду для выполненияdelete
действия.s
команда выполнена успешно, то используйтеtloop
команду force,sed
чтобы перейти кlabel
названномуloop
, что сделает тот же цикл для следующих строк, при этом не будет повторяющихся последовательных строк строки, которая естьlatest printed
; в противном случае используйтеD
команду дляdelete
строки, которая совпадает сlatest-printed line
, и принудительныйsed
переход к первой команде, которая являетсяp
командой, содержимое текущейpattern space
является следующей новой строкой.источник
busybox echo -e "1\n2\n2\n3\n3\n3\n4\n4\n4\n4\n5" | busybox sed -nr "$!N;/^(.*)\n\1$/!P;D"
Этого можно добиться с помощью awk.
Ниже линии будут отображаться уникальные значения.
Вы можете вывести эти уникальные значения в новый файл
новый файл uniq_file_name будет содержать только уникальные значения, без дубликатов
источник
Удаляет повторяющиеся строки с помощью awk.
источник
cat
uniq