Как для grep или поиска шаблонов из 3 слов в файле и их печати вместе с содержимым между вторым и третьим словом Pattern [закрыто]

Puedes hacer algo como esto:

echo date | script -q bigram-trace.txt

Resultado:

$ cat bigram-trace.txt
date
sh-4.4$ date
Sun, Feb 18, 2018  6:22:13 PM
sh-4.4$ exit

O sin tubo:

script -q bigram-trace.txt <<'eof'
date
eof
-3
25.09.2018, 20:05
3 ответа

Теперь, когда вы указали, что нам нужно пропустить все ложные шаблоны, которые могут появиться вне ожидаемого порядка, нам нужно что-то более сложное, например, конечный автомат.

Вот пример гораздо более сложного исходного файла, который включает в себя все странные пограничные случаи и комментарии:

a
#### Pattern 2 #### Ignore because we have not yet seen Pattern 1
z
#### Pattern 3 #### Ignore because we have not yet seen Pattern 1, 2
b
#### Pattern 1 #### (!!)
#### Pattern 1 #### Don't print 1 in between 1-2
c
d
#### Pattern 2 #### (!!)
e
#### Pattern 1 #### Don't print 1 in between 2-3
#### Pattern 2 #### ?? Don't print 2 in between 2-3 ??
f
#### Pattern 3 #### (!!)
?? Now reset and accept look for the start of a NEW 1,2,3 cycle. Right ??
g
#### Pattern 3 #### Ignore
#### Pattern 2 #### Ignore
#### Pattern 3 #### Ignore
h
#### Pattern 1 #### (!!)
i
#### Pattern 3 #### Don't print 3 in between 1-2
j
#### Pattern 2 #### (!!)
k
l
#### Pattern 3 #### (!!)
m
n

Ожидаемый результат:

#### Pattern 1 #### (!!)
#### Pattern 2 #### (!!)
e
f
#### Pattern 3 #### (!!)
#### Pattern 1 #### (!!)
#### Pattern 2 #### (!!)
k
l
#### Pattern 3 #### (!!)

Похоже, нам нужно построить конечный автомат с 3 состояниями. Итак, теперь мы пишем полноценный сценарий....

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

## Linear state machine 0 --> 1 --> 2 --> 0
my @patterns = (
    qr(Pattern 1),  # state 0: noprint;              match this: noprint && state = 1
    qr(Pattern 2),  # state 1: noprint;              match this:   print && state = 2
    qr(Pattern 3)   # state 2: print (NOT patterns); match this: print   && stage = 0
    );
my $state = 0;

while (<>) {
    if (0 == $state) {
        if (m/$patterns[0]/) {
            ++$state;
        }
    } elsif (1 == $state) {
        if (m/$patterns[1]/) {
            print;
            ++$state;
        }
    } elsif (2 == $state) {
        if (m/$patterns[0]/ || m/$patterns[1]/) {
            # Ignore
        } elsif (m/$patterns[2]/) {
            print;
            $state = 0;
        } else {
            print;
        }
    } else {
        die "Bad programmer! ($state)";
    }
}

Как-то некрасиво. Можно реализовать более гибкий конечный автомат с хэшем [$state_num, $pattern_num] => sub {...action... }где пропустить/игнорировать — это действие по умолчанию для любой комбинации [состояние, шаблон], которая не появляется в хэше. Но это остается в качестве упражнения для восторженного читателя;-)

1
28.01.2020, 05:19

Довольно просто с sed:

sed -n '/Pattern 1/p; /Pattern 2/,/Pattern 3/p' file
####Pattern 1####
####Pattern 2####
line 1
line 2
line 3
line 4
line 5
line...
####Pattern 3####
####Pattern 1####
####Pattern 2####
line 1
line 2
line 3
line 4
####Pattern 3####

Имея входной файл Дугласа, мы можем получить этот awk, который выдает ожидаемый результат. Как и его ответ, это конечный автомат, который использует пару логических переменных для определения состояния :

.
awk -v p1="#### Pattern 1 ####" \
    -v p2="#### Pattern 2 ####" \
    -v p3="#### Pattern 3 ####" '
        $0 ~ p1 && !have_p1 && !in_p2p3             {have_p1 = $0}
        $0 ~ p2 &&  have_p1 && !in_p2p3             {in_p2p3 = 1; print have_p1; print}
        have_p1 &&  in_p2p3 && $0 !~ p1 && $0 !~ p2 {print}
        $0 ~ p3 &&  in_p2p3                         {in_p2p3 = 0; have_p1 = ""}
' file
#### Pattern 1 #### (!!)
#### Pattern 2 #### (!!)
e
f
#### Pattern 3 #### (!!)
#### Pattern 1 #### (!!)
#### Pattern 2 #### (!!)
k
l
#### Pattern 3 #### (!!)
0
28.01.2020, 05:19

Вот один из способов сделать это, дважды просматривая входной файл. В первый раз он проходит и смотрит только на линии шаблона, и по ним мы определяем переходы состояний и отмечаем требуемое :1 ->2 ->3.

code=$(< INPUT_FILE \
    sed -e '/Pattern [1-3]/!d;=' |\
    sed -e 'N;s/\n/:/'                     |\
    sed -e '
        /Pattern 1/!d;$d;N
        /\n.*Pattern 1/D
        /Pattern 2/!d;$d;N
        /Pattern 3/!d
    '                                      |\
    sed -e '
        s/:.*//;N;s///;N;s///
        s/\n.*\n/,/;s/$/p/
    '
)

# and having computed the right ranges to print, we now enter the 2nd pass
sed -ne "$code" inp |\
sed -e '/Pattern 1/,/Pattern 2/!b' -e '//!d'

и если вам нужен только один вызов sed, вы можете сделать это, как показано ниже:

sed -e '
    /Pattern 1/,/Pattern 2/!d    ;# reject non-interesting range
    /Pattern 1/h                 ;# store in hold beginning of range
    /Pattern [23]/H              ;# store pattern 2 and 3 lines in hold too
    /Pattern 2/!d                ;# not at end of range... delete
    g;/Pattern 3/d               ;# range seen completed, now check whether pattern 3 came
                                 ;# during the 1->2 search, and delete everything & restart
                                 ;# afresh if it did. otherwise, empty the pattern space in
                                 ;# preparation for reading the 2->3
    s/.*//

    :loop                        ;# setup a while(1) loop to read 2->3 range
        $d;N                     ;# read the next line into the pattern space provided
                                 ;# it isnt the last
        /Pattern [12]/d          ;# if we encounter pattern 1/2 then drop everything & start afresh
        /Pattern 3/{             ;# we checked 1/2 didnot come and 3 came
            s/^\n//;H;g;b
        }
    bloop
' input-file.txt

Вот подход, основанный на FSM -, использующий hashesдля кодирования текущего -состояния, следующего -отношения состояния (формулировки машины Мили -):

perl -lne '
    BEGIN {
        sub getLinetype {
            local $_ = @_ ? shift : $_;
            return
                /Pattern 1/ ? "PATT_1" :
                /Pattern 2/ ? "PATT_2" :
                /Pattern 3/ ? "PATT_3" :
                "NON_PATT_123";
        }

        # ---------------------------------------------------------------------
        #     PS      line_type             NS             action
        # ---------------------------------------------------------------------
        $h{ RESET  }{ PATT_1       } = [ "STATE1", sub { @A = ( $_ ) } ];
        $h{ RESET  }{ PATT_2       } = [ "RESET",  sub { @A = ()     } ];
        $h{ RESET  }{ PATT_3       } = [ "RESET",  sub { @A = ()     } ];
        $h{ RESET  }{ NON_PATT_123 } = [ "RESET",  sub { @A = ()     } ];
        # ---------------------------------------------------------------------
        $h{ STATE1 }{ PATT_1       } = [ "STATE1", sub { @A = ( $_ ) } ];
        $h{ STATE1 }{ PATT_2       } = [ "STATE2", sub { push @A, $_ } ];
        $h{ STATE1 }{ PATT_3       } = [ "RESET",  sub { @A = ()     } ];
        $h{ STATE1 }{ NON_PATT_123 } = [ "STATE1", sub {     ;       } ];
        # ---------------------------------------------------------------------
        $h{ STATE2 }{ PATT_1       } = [ "STATE1", sub { @A = ( $_ ) } ];
        $h{ STATE2 }{ PATT_2       } = [ "RESET",  sub { @A = ()     } ];
        $h{ STATE2 }{ PATT_3       } = [ "STATE3", sub { print for splice(@A), $_ } ];
        $h{ STATE2 }{ NON_PATT_123 } = [ "STATE2", sub { push @A, $_ } ];
        # ---------------------------------------------------------------------
        $h{ STATE3 }{ PATT_1       } = [ "STATE1", sub { @A = ( $_ ) } ];
        $h{ STATE3 }{ PATT_2       } = [ "RESET",  sub { @A = ()     } ];
        $h{ STATE3 }{ PATT_3       } = [ "RESET",  sub { @A = ()     } ];
        $h{ STATE3 }{ NON_PATT_123 } = [ "RESET",  sub { @A = ()     } ];
        # ---------------------------------------------------------------------

        $present_state = "RESET";
    }

    my $line_type = getLinetype();

    my $next_state = $h{$present_state}{$line_type}->[0];
    my $action_ref = $h{$present_state}{$line_type}->[1];

    $action_ref->();

    $present_state = $next_state;
' input-file.txt
0
28.01.2020, 05:19

Теги

Похожие вопросы