Назад | Перейти на главную страницу

Поиск и удаление строк, соответствующих шаблону, вместе с комментариями в предыдущей строке, если таковые имеются

У меня есть требование написать сценарий оболочки в csh для поиска и удаления строк, соответствующих шаблону, вместе с комментариями в предыдущей строке, если таковые имеются. Например, если в моем файле есть следующие строки

Shell script
#this is  a test
pattern1
format1
pattern2
format2
#format3
pattern3

Если шаблон поиска - "шаблон", результат должен быть следующим

Shell script
format1
format2

Чтобы быть более точным, следует удалить строки, которые имеют шаблон, и предыдущую строку, если она начинается с "#".

Спасибо за помощь

Вот sed версия. Некоторые версии sed может потребоваться разделить части этого на несколько -e статьи.

sed '$b;N;/^#.*\npattern.*$/ ! {P;D}; :c; $d; s/.*\n//;N;/^#.*\npattern.*$/ {bc}; /^pattern/d; D' patterns

Вот версия файла сценария этого однострочника с комментариями:

#!/bin/sed -f

# Search for a combination of a comment followed by a pattern
# until that, print what you find.
$b
N
/^#.*\npattern.*$/ ! {
P
D
}

:c
# Got a comment and a pattern combination in pattern space.
# At the end of the file we simply exit
$d

# Else, we keep reading lines with `N' until we
# find a different one
s/.*\n//
N
/^#.*\npattern.*$/ {
bc
}

# Remove standalone lines that have "pattern"
/^pattern/d

# Remove the last instance of the combination
# and go back to the top
D

Это основано на сценарии в info sed раздел 4.16 «Удалить все повторяющиеся строки» (uniq -u).

Вероятно, лучший способ написать это логически, но я думаю, что это может сделать это:

#!/usr/bin/perl
use strict;
use warnings;


my $previous_line = '';
while(<>) {
    if ( /pattern/ ) {
        if ( (! ($previous_line =~ /^#/)) && (! ($previous_line =~ /pattern/))) {
            print $previous_line;
        }
    } elsif (! ($previous_line =~ /pattern/)) {
        print $previous_line;
    }
    $previous_line = $_;
}
print $previous_line if not ($previous_line =~ /pattern/);

По сути, цикл - это линия позади предыдущей. Он говорит, что можно распечатать предыдущая строка если:

  1. Если текущая строка соответствует шаблону: можно печатать предыдущую, если предыдущая также не соответствует шаблону, или это был комментарий.
  2. Если эта строка не является шаблоном, можно распечатать предыдущую строку, если она не соответствует шаблону.

Вы можете просто сохранить код в файл и использовать его так: perl thefile.pl textfile_you_want_to_filter

Вот однострочное решение на Perl (не в оболочке C). Вы можете изменить /pattern/ регулярное выражение посередине.

perl -ne 'if(/^#/){$c=$_}elsif(!/pattern/){print$c,$_;$c=""}else{$c=""}' <file.in

Прежде всего никто никогда не должен использовать csh ни за что - он устаревший и неработающий (не "под"). Во-вторых, я сомневаюсь, что справится с этой задачей. В-третьих, гораздо более вероятно, что awk, sed или даже Perl будет гораздо лучшим инструментом для этой задачи.

awk '/^#/ {printf line; line=$0"\n"; next} /pattern/ {line=""} ! /pattern/ {printf line; print; line=""}'

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

Это должен быть сценарий оболочки?

  1. открыть файл с vi
  2. :g/<pattern>/d
  3. повторите, если необходимо, для дополнительных типов шаблонов, если вы не можете повторно выразить шаблон
  4. :g/^#/d

может быть эффективно воспроизведен с помощью sed, если он должен быть написан скриптом

редактировать:

1. создать файл .sedscript:

/pattern/d
/^#/d

2.sed -f .sedscript <inputfile> > <outputfile>

Это не удовлетворяет требованию удалить предыдущую строку, но ваш пример, похоже, не требует этой функции.