Abaixo está o texto no arquivo:

Pseudo name=Apple Code=42B state=fault Pseudo name=Prance Code=43B state=good 

Eu preciso fazer o grep para “42B” e obtenha a saída do texto acima como:

Pseudo name=Apple Code=42B state=fault 

Alguém tem uma ideia de como fazer isso usando grep / awk / sed?

Comentários

  • Você marcou esta pergunta apenas com " grep ". Você está procurando apenas " grep " soluções então? Na pergunta, você especifica awk & sed também. Podemos adicionar essas tags? Eu não tinha ' certeza de sua intenção quando editei a pergunta ontem à noite.
  • stackoverflow.com/ perguntas / 12024410 / …

Resposta

Com awk

awk -v RS="" "/42B/" file 

RS= altera o separador de registro de entrada de uma nova linha para linhas em branco. Se algum campo em um registro contiver /42B/ imprima o registro.

"" (a string nula) é mágico valor usado para representar linhas em branco de acordo com POSIX :

Se RS é nulo, então os registros são separados por sequências que consistem em um <newline> mais um ou mais em branco linhas, linhas em branco iniciais ou finais não devem resultar em registros vazios no início ou no final da entrada, e um <newline> deve sempre ser um separador de campo, não importa o valor de FS é.

Os parágrafos de saída não ser separado, pois o separador de saída permanece uma única nova linha. Para garantir que haja uma linha em branco entre os parágrafos de saída, defina o separador de registro de saída para duas novas linhas:

awk -v RS="" -v ORS="\n\n" "/42B/" file 

Comentários

  • +1 para uma solução elegante. Você não ' não precisa redirecionar o arquivo …
  • dedos estavam no piloto automático.
  • @jasonwryan, a menos que você precise de acesso ao nome do arquivo dentro de awk (FILENAME), ' não é uma má ideia usar o redirecionamento, pois evita problemas para nome de arquivo contendo = ou começando com - (ou sendo -), cria mensagens de erro consistentes e evita executar awk ou realizar outros redirecionamentos se o arquivo de entrada não puder ' ser aberto.

Resposta

Supondo que os dados sejam estruturados de forma que sejam sempre a linha anterior e posterior que você deseja, você pode usar grep “s -A (depois) e -B (antes) muda para dizer a ele para incluir a 1 linha antes da correspondência e 1 linha depois dela:

$ grep -A 1 -B 1 "42B" sample.txt Pseudo name=Apple Code=42B state=fault 

Se você quiser mesmo número de linhas antes e depois do termo de pesquisa, você pode usar a -C (contexto) switch:

$ grep -C 1 "42B" sample.txt Pseudo name=Apple Code=42B state=fault 

Se você “gostaria de ser mais rigoroso ao combinar as várias linhas, você pode usar a ferramenta pcregrep , para combinar um padrão em várias linhas:

$ pcregrep -M "Pseudo.*\n.*42B.*\nstate.*" sample.txt Pseudo name=Apple Code=42B state=fault 

O padrão acima corresponde à seguinte:

  • -M – várias linhas
  • "Pseudo.*\n.*42B.*\nstate.*" – corresponde a um grupo de strings em que a primeira string começa com a palavra "Pseudo" seguido por qualquer caractere até o final da linha \n, seguido por qualquer caractere até a string "42B" seguido por qualquer caractere até outro fim de linha (\n), seguido pela string "state" seguida por quaisquer caracteres.

Comentários

  • -C (contexto) pode ser usado como um atalho, se -A e -B forem iguais.
  • @DavidBaggerman – obrigado. Adicionado à resposta.
  • Por que o um voto negativo? Isso responde à pergunta.

Resposta

O grep de alguns sabores do Unix têm o sinalizador -p para “paragraph”. Eu sei que o AIX faz .

grep -p 42B <myfile> 

faria exatamente o que você está pedindo lá . YMMV e GNU grep não têm este sinalizador.

Comentários

  • Ter o sinalizador -p seria maravilhoso. Especialmente se usado junto com -v para que você possa excluir parágrafos inteiros da saída.

Resposta

Provavelmente existe uma maneira igualmente fácil de fazer isso com awk, mas em perl:

cat file | perl -ne "BEGIN { $/="\n\n" }; print if $_ =~ /42B/;" 

Isso basicamente diz para dividir o arquivo em partes delimitadas por linhas em branco e, em seguida, imprimir apenas as partes que correspondem à sua expressão regular.

Comentários

  • Isso pode ser simplificado usando opções e atalhos e perdendo o uso inútil de cat ; perl -00 -ne 'print if /42B/' file

Resposta

Uma outra solução perl, sem um linha vazia à direita:

perl -00ne "if ($_ =~ /42B/) {chomp($_); printf "%s\n",$_}" foo 

Exemplo

% perl -00ne "if ($_ =~ /42B/) {chomp($_); printf "%s\n",$_}" foo Pseudo name=Apple Code=42B state=fault % cat foo Pseudo name=Apple Code=42B state=fault Pseudo name=Prance Code=43B state=good 

Comentários

  • Ou mais curtos (e, portanto, mais legíveis), como o triplo escreveu em um comentário: perl -00 -ne 'print if /42B/' file.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *