Удалить повторяющиеся линии, только если они соответствуют шаблону - PullRequest
0 голосов
/ 03 марта 2019

На этот вопрос есть отличный ответ о том, что вы можете использовать awk '!seen[$0]++' file.txt для удаления непоследовательных повторяющихся строк из файла.Как я могу удалить непоследовательные повторяющиеся строки из файла, только если они соответствуют шаблону?например, только если они содержат строку "#####"

Пример ввода

deleteme.txt ##########
1219:                            'PCM BE PTP'
deleteme.txt ##########
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1222:                          , 'PCM BE PTP UT'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1223:                          , 'PCM BE PTP'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1225:                          , 'PCM FE/MID PTP'

Требуемый вывод

deleteme.txt ##########
1219:                            'PCM BE PTP'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1222:                          , 'PCM BE PTP UT'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
1223:                          , 'PCM BE PTP'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
1225:                          , 'PCM FE/MID PTP'

Ответы [ 4 ]

0 голосов
/ 04 марта 2019

Это может работать для вас (GNU sed):

sed '/#$/{G;/^\(\S*\s\).*\1/!P;h;d}' file

Все строки, кроме интересующих, печатаются как обычно.

Добавлять предыдущие интересующие строки к текущей строке ииспользуя сопоставление с образцом, если такая линия не встречалась ранее, выведите ее.Затем сохраните пространство шаблона обратно в поле ожидания, готовый к следующему совпадению, и удалите пространство шаблона.

0 голосов
/ 03 марта 2019

Всякий раз, когда я думаю о сопоставлении шаблонов и выборочной печати, я думаю о Практическом извлечении и языке отчетов: Perl!Вот Perl One-Liner, который делает то, что вы просите.Вы должны быть в состоянии скопировать и вставить это в оболочку и заставить ее работать:

perl -wnle 'BEGIN { $rows_with_five_hashes = {}; } $thisrow = $_; if ($thisrow =~ /[#]{5}/) { if (!exists $rows_with_five_hashes->{$thisrow}) { print; } $rows_with_five_hashes->{$thisrow}++; } else { print; }' input.txt

Вот тот же Perl с разрывами строк и комментариями для ясности (примечание: это не исполняемый как есть):

BEGIN {
  # create a counter for rows that match the pattern
  $rows_with_five_hashes = {}; 
} 
# capture the row from the input file
$thisrow = $_;
if ($thisrow =~ /[#]{5}/) { 
  if (!exists $rows_with_five_hashes->{$thisrow}) { 
    # this row matches the pattern and we haven't seen it before
    print; 
  } 
  # Increment the counter for rows that match the pattern.
  # Do this AFTER we print, or else our "exists" print logic fails.
  $rows_with_five_hashes->{$thisrow}++;
} 
else { 
  # print all rows that don't match the pattern
  print;
}

В Ruby есть аналогичные функции «одной строки» для запуска кода непосредственно в командной строке (большая часть которого заимствована из Perl).

Для получения дополнительной информации о wnleпереключатели командной строки, посмотрите документы Perl об этом .Если у вас было много файлов, которые вы хотели изменить вместо и сохранить резервные копии оригиналов с помощью одной команды Perl, проверьте переключатель -i в этих документах.

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

0 голосов
/ 04 марта 2019

Попробуйте это решение для регулярных выражений командной строки Perl, используя режим файла slurp.

perl -0777 -ne ' $z=$y=$_; 
                 while( $y ne $x) 
                 { $z=~s/(^[^\n]+?\s+##########.*?$)(.+?)\K(\1\n)//gmse ; $x=$y ;$y=$z } ; 
                 print "$z" '

с заданными входными данными

$ cat toucan.txt
deleteme.txt ##########
1219:                            'PCM BE PTP'
deleteme.txt ##########
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1222:                          , 'PCM BE PTP UT'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1223:                          , 'PCM BE PTP'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1225:                          , 'PCM FE/MID PTP'

$ perl -0777 -ne ' $z=$y=$_; while( $y ne $x) { $z=~s/(^[^\n]+?\s+##########.*?$)(.+?)\K(\1\n)//gmse ; $x=$y ;$y=$z } ; print "$z" ' toucan.txt
deleteme.txt ##########
1219:                            'PCM BE PTP'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1222:                          , 'PCM BE PTP UT'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
1223:                          , 'PCM BE PTP'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
1225:                          , 'PCM FE/MID PTP'

$
0 голосов
/ 03 марта 2019

Вы можете использовать

awk '!/#####/ || !seen[$0]++'

Или, как Эд Мортон предлагает , синоним:

awk '!(/#####/ && seen[$0]++)'

Здесь !seen[$0]++ делает то же, что и обычно, он удалит любую дублированную строку.Часть !/#####/ соответствует строкам, которые содержат шаблон #####, и отменяет совпадение.Два шаблона в сочетании с || удаляют все повторяющиеся линии, имеющие внутри шаблон #####.

См. online awk demo :

s="deleteme.txt ##########
1219:                            'PCM BE PTP'
deleteme.txt ##########
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1222:                          , 'PCM BE PTP UT'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1223  #####:                          , 'PCM BE PTP'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1225:                          , 'PCM FE/MID PTP'"
awk '!/#####/ || !seen[$0]++' <<< "$s"

Выход:

deleteme.txt ##########
1219:                            'PCM BE PTP'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
deleteme2.txt ##########
1222:                          , 'PCM BE PTP UT'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
1223  #####:                          , 'PCM BE PTP'
1221:                          , 'PCM FE/MID PTP UT','PCM IA 1 PTP'
1225:                          , 'PCM FE/MID PTP'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...