Como imprimir uma linha se essa linha ou a próxima linha não contiver uma string específica

7

Input.txt:

    8B0C
    remove
    8B0D
    remove
    8B0E
    remove
    8B0F
    8B10
    remove
    8B14
    remove
    8B15
    remove
    8B16
    remove
    8B17
    remove
    8AC0
    8AC1
    remove
    8AC2
    remove
    8AC3
    remove
    8AE4
    8AE5
    8AE6
    remove

Saída desejada:

    8B0F
    8AC0
    8AE4
    8AE5

Eu quero imprimir uma linha se essa linha ou a próxima linha não contiver 'remover'. Estou usando o solaris 5.10, KSH.

    
por ayrton_senna 16.07.2015 / 21:04

3 respostas

12

com sed :

sed '$!N;/remove/!P;D' infile

Isso puxa a linha N ext para o espaço padrão (se não for ! na linha $ t) e verifica se o espaço padrão corresponde a remove . Se isso não acontecer (significa que nenhuma das duas linhas no espaço padrão contém a string remove ), ele P rints até o primeiro caractere \n ewline (ou seja, a primeira linha será impressa). Então, D elimina o primeiro caractere \n ewline e reinicia o ciclo. Desta forma, nunca há mais do que duas linhas no espaço padrão.

É mais fácil entender o N , P , D cycle se você adicionar l antes e depois do N para ver o espaço padrão:

sed 'l;$!N;l;/remove/!P;D' infile

então, usando apenas as últimas seis linhas do seu exemplo:

    8AC3
    remove
    8AE4
    8AE5
    8AE6
    remove

o último comando sai:

    8AC3$
    8AC3\n    remove$
    remove$
    remove\n    8AE4$
    8AE4$
    8AE4\n    8AE5$
    8AE4
    8AE5$
    8AE5\n    8AE6$
    8AE5
    8AE6$
    8AE6\n    remove$
    remove$
    remove$

Aqui está uma breve explicação:

cmd        output            cmd
l     8AC3$                  N # read in the next line
l     8AC3\n    remove$      D # delete up to \n (pattern space matches so no P)
l     remove$                N # read in the next line
l     remove\n    8AE4$      D # delete up to \n (pattern space matches so no P)
l     8AE4$                  N # read in the next line
l     8AE4\n    8AE5$        # pattern space doesn't match so print up to \n
P     8AE4                   D # delete up to \n
l     8AE5$                  N # read in the next line
l     8AE5\n    8AE6$        # pattern space doesn't match so print up to \n
P     8AE5                   D # delete up to \n 
l     8AE6$                  N # read in the next line
l     8AE6\n    remove$      D # delete up to \n (pattern space matches so no P)
l     remove$                # last line so no N 
l     remove$                D # delete (pattern space matches so no P)
    
por 16.07.2015 / 21:24
4
awk '
    !/remove/ && NR > 1 && prev !~ /remove/ {print prev} 
    {prev = $0} 
    END {if (!/remove/) print}
' Input.txt 
    
por 16.07.2015 / 21:23
2
gawk 'BEGIN{ RS="remove\n"; ORS="" }
      RT{ print gensub("[^\n]*\n$","","") }; !RT{ print }' file

O método acima não lê Registros linha-por-linha , ao invés de ler Registros de várias linhas de um Separador de Registros (RS) para o próximo (ou final -of-file) - o RS é a própria linha "remove" (incluindo o seu rastreio '\ n).

O teste !RT é necessário para quando a última linha não é uma linha RS .
RT , um gawk-ism , é o texto real do registro atual RS .
gensub é também um gawk-ism .

Se você precisar verificar uma linha de marcador que corresponde a "remover" em qualquer lugar da linha, vs. uma linha que é igual a "remove", basta alterar o Separador de registro para:

'RS="[^\n]*remove[^\n]*\n"'  

Saída:

8B0F
8AC0
8AE4
8AE5
    
por 16.07.2015 / 23:38