Procura uma linha (string) entre outras duas linhas diferentes

1

Estou procurando por um comando liner (da melhor maneira) que pode encontrar se uma string / linha específica é apresentada entre outras duas linhas. Eu procuro e só encontro o commad para obter conteúdo entre duas linhas, mas como posso verificar se alguma coisa está presente ou não ..

.....
 1 a 2 b 3
 4
   5
.....
 1 c 2 d 3
 4
   5
.....
 1 e 2 f 3
   5
.....

Eu encontrei isto:

sed -n '/^ 1 .* 2 .* 3$/,/^ 5$/p'

o resultado com este comando corta as linhas indesejadas boas para iniciar (linhas de corte "...."), mas ainda não sabe como verificar se "4" é apresentado entre:

 1 a 2 b 3
 4
   5
 1 c 2 d 3
 4
   5
 1 e 2 f 3
   5

A saída deve ficar assim:

 "4" is missing after "1 e 2 f 3"

Apenas para OR (é ainda melhor):

"1 e 2 f 3"
    
por loken 24.03.2018 / 02:14

2 respostas

0

sed não é a ferramenta certa para o trabalho. No entanto, provavelmente ainda podemos fazer isso em sed :

sed -n '/^ 1 .* 2 .* 3$/,/^ 5$/ { /^ 1 .* 2 .* 3$/ { h }; /^ 4$/ { x; s/.*//; x;}; /^ 5$/ { x; p; x} }' filename | grep -v -e '^$'

Aqui está apenas a parte que adicionei ao seu bloco de intervalo:

/^ 1 .* 2 .* 3$/ { h }; /^ 4$/ { x; s/.*//; x;}; /^ 5$/ { x; p; x}

Leia isto como:

se a linha corresponder a regex /^ 1 .* 2 .* 3$/ e, em seguida, h (armazenar linha no buffer de retenção)
Se a linha corresponder a regex /^ 4$/ , então x (buffer de troca, ou seja, fazer operações se aplicam a armazenar buffer em vez de buffer padrão), substitua tudo em buffer de retenção * e x novamente (para voltar ao buffer padrão)
Se a linha corresponder a ^ 5$/ , mude para o buffer de retenção, p (imprima o conteúdo do buffer de retenção) e volte para o buffer padrão

* Infelizmente, s/.*// não exclui linhas no buffer de espera. A exclusão de linhas no buffer de retenção parece difícil, então nos livramos delas, canalizando para o grep -v -e '^$' .

Atualizar

Esta versão imprime o nome do arquivo após a correspondência (usando o comando F ) e gerencia sem canalizar para grep . Obrigado Paulo!

sed -n '/^ 1 .* 2 .* 3$/,/^ 5$/ { /^ 1 .* 2 .* 3$/ { h }; /^ 4$/ { x; s/.*//; x;}; /^ 5$/ { x; /^$/ !{ p; F }; x} }' data
    
por 24.03.2018 / 06:56
0

Thanx @sneep por mencionar perl :

perl -lane 'if($n=/^ 1 .* 2 .* 3$/../^ *5$/) {$s=$_ if $n==1; $s="" if /^ *4$/; print "$ARGV: $s" if $s && $n=~/E/}' /otherdir/*

Espero ter entendido o problema corretamente: adicione o OP para especificar mais detalhes.

Explicação:

perl Linguagem de extração e relatórios práticos.
-lane normalmente é útil para one-liners.
' das instruções do programa real
if(/^ 1 .* 2 .* 3$/../^ *5$/) { executa as ações entre chaves somente para partes de texto que começam com uma linha correspondente a /^ 1 .* 2 .* 3$/ e terminam com uma linha que contém um único dígito 5 , possivelmente precedido por qualquer número de espaços. • $n=/^ 1 .* 2 .* 3$/../^ *5$/ rastreia o número da linha na parte do texto.
$s=$_ if $n==1; salve a primeira linha da parte do texto na variável $s .
$s="" if /^ *4$/; procura a string desejada: um único dígito 4 que vem depois de qualquer número de espaços. Se encontrado, exclua a linha salva anteriormente para a variável $s .
print "$ARGV: $s" if $s && $n=~/E/ imprime o nome do arquivo, dois pontos, um espaço e a linha que iniciou a parte do texto atual se a variável $s contiver qualquer texto e o $n contador mostrar que a última linha da parte do texto foi atingida.
} end das ações a serem executadas na parte do texto.
' end das instruções do programa.
/otherdir/* processa todos os arquivos no /otherdir/ caminho

    
por 17.04.2018 / 17:13

Tags