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 executarawk
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
.