Retornar apenas a parte de uma linha após um padrão correspondente

109

Portanto, abrir um arquivo cate usá grep-lo para obter linhas correspondentes só me leva a um ponto em que estou trabalhando com o conjunto de logs específico com o qual estou lidando. Ele precisa de uma maneira de corresponder linhas a um padrão, mas apenas para retornar a parte da linha após a correspondência. A parte antes e depois da partida variará consistentemente. Eu brinquei com o uso de sedou awk, mas não consegui descobrir como filtrar a linha para excluir a parte antes da partida ou apenas retornar a parte após a partida, ou funcionará. Este é um exemplo de uma linha que eu preciso filtrar:

2011-11-07T05:37:43-08:00 <0.4> isi-udb5-ash4-1(id1) /boot/kernel.amd64/kernel: [gmp_info.c:1758](pid 40370="kt: gmp-drive-updat")(tid=100872) new group: <15,1773>: { 1:0-25,27-34,37-38, 2:0-33,35-36, 3:0-35, 4:0-9,11-14,16-32,34-38, 5:0-35, 6:0-15,17-36, 7:0-16,18-36, 8:0-14,16-32,34-36, 9:0-10,12-36, 10-11:0-35, 12:0-5,7-30,32-35, 13-19:0-35, 20:0,2-35, down: 8:15, soft_failed: 1:27, 8:15, stalled: 12:6,31, 20:1 }

A parte que eu preciso é tudo depois de "parado".

O pano de fundo por trás disso é que eu posso descobrir com que frequência algo pára:

cat messages | grep stalled | wc -l

O que eu preciso fazer é descobrir quantas vezes um determinado nó parou (indicado pela parte antes de cada dois pontos depois de "parado". Se eu apenas esperar por isso (ou seja, 20 :), ele pode retornar linhas que apresentam falhas suaves, mas sem interrupções, o que não me ajuda.Preciso filtrar apenas a parte paralisada para que eu possa receber um nó específico daqueles que pararam.

Para todos os efeitos, este é um sistema freebsd com utilitários padrão do GNU, mas não consigo instalar nada extra para ajudar.

MaQleod
fonte
@ Gilles, é estranho como isso não apareceu quando eu procurei, embora eu não tenha usado o título com o qual eu acabei usando ... mas ele não apareceu na tela abaixo do meu título. Enfim, isso de lado, isso pode me levar aonde eu quero, embora eu precise de toda a linha após a partida, não a primeira palavra - mas pode não levar muita mudança.
MaQleod
Seu título foi péssimo. Eu roubei o seu, o que é muito bom. Pegue a sedsolução e não trate especialmente os espaços em branco.
Gilles
@ Gilles, isso é algo que não sei ao certo como fazer. Eu ainda estou aprendendo sed.
MaQleod 8/11/11
semelhante a unix.stackexchange.com/questions/24089/… também.
Tim Tim Kennedy
1
@ shaa0601 Não entendi sua pergunta, é especialmente difícil seguir um comentário sem formatação. Faça uma pergunta nova e independente.
Gilles

Respostas:

141

A ferramenta canônica para isso seria sed.

sed -n -e 's/^.*stalled: //p'

Explicação detalhada:

  • -n significa não imprimir nada por padrão.
  • -e é seguido por um comando sed.
  • s é o comando de substituição de padrão.
  • A expressão regular ^.*stalled:corresponde ao padrão que você está procurando, além de qualquer texto anterior ( .*ou seja, qualquer texto, com uma inicial ^para dizer que a correspondência começa no início da linha). Observe que se stalled:ocorrer várias vezes na linha, isso corresponderá à última ocorrência.
  • A partida, ou seja, tudo na linha até stalled:, é substituída pela sequência vazia (ou seja, excluída).
  • O pmeio final para imprimir a linha transformada.

Se você deseja reter a parte correspondente, use uma referência posterior: \1na peça de substituição designa o que está dentro de um grupo \(…\)no padrão. Aqui, você pode escrever stalled:novamente na peça de substituição; esse recurso é útil quando o padrão que você procura é mais geral do que uma sequência simples.

sed -n -e 's/^.*\(stalled: \)/\1/p'

Às vezes, você deseja remover a parte da linha após a partida. Você pode incluí-lo na correspondência incluindo .*$no final do padrão (qualquer texto .*seguido pelo final da linha $). A menos que você coloque essa parte em um grupo que você referencia no texto de substituição, o final da linha não estará na saída.

Como uma ilustração adicional de grupos e referências anteriores, esse comando troca a parte antes da partida e a parte após a partida.

sed -n -e 's/^\(.*\)\(stalled: \)\(.*\)$/\3\2\1/p'
Gilles
fonte
Eu tentei os dois primeiros exemplos e parece travar. Não recebo uma mensagem de erro, nem recebo um novo prompt, apenas nada.
MaQleod 8/11/11
2
@MaQleod Ah, está aguardando a entrada na entrada padrão, que é o terminal porque você não o redirecionou. Aqui você faria um redirecionamento de entrada sed … <messages, já que deseja processar dados de um arquivo. A agir em dados produzidos por outro comando, você pode usar um tubo: somecommand | sed ….
Gilles
1
certo, fim do dia apagão lá. comando funciona perfeitamente, obrigado.
MaQleod
1
A melhor explicação sobre sed que já vi até agora - obrigado!
Jon Wadsworth
1
@ungalcrys Versão mais curta de quê? Isso não é equivalente a nenhum dos comandos na minha resposta. Eu recomendo escrevê-lo, sed 's/^.*stalled//'pois -ré específico para Linux e não funciona em outros sistemas, como o macOS, e aqui você não está obtendo nenhum benefício.
Gilles
72

A outra ferramenta canônica que você já usa grep::

Por exemplo:

grep -o 'stalled.*'

Tem o mesmo resultado que a segunda opção de Gilles:

sed -n -e 's/^.*\(stalled: \)/\1/p'

A -oflag retorna a --only-matchingparte da expressão, portanto, não a linha inteira que é, é claro, normalmente feita pelo grep.

Para remover o "parado:" da saída, podemos usar uma terceira ferramenta canônica, corte:

grep -o 'stalled.*' | cut -f2- -d:

O cutcomando usa delimitador :e imprime o campo 2 até o final. É uma questão de preferência, é claro, mas a cutsintaxe é muito fácil de lembrar.

Anne van Rossum
fonte
1
Obrigado por mencionar a -oopção! Eu gostaria de salientar que grepnão reconhece o \ncomo uma nova linha; portanto, seu primeiro exemplo corresponde apenas ao primeiro ncaractere. Por exemplo, echo "Hello Anne" | grep -o 'A[^\n]*'retorna a string A. No entanto, echo "Hello Anne" | grep -o 'A.*'retorna o esperado Anne, pois .corresponde a qualquer caractere, exceto a nova linha.
adamlamar
1
Observe que as aspas ao redor do cutdelimitador -d':'são removidas por @poige. Acho mais fácil lembrar com aspas, por exemplo, com -d' 'ou -d';'.
Anne van Rossum
De acordo com a sua conclusão, deve ser mais fácil lembrar-se de usar aspas -f 2também. Sério, por que não?
poige
Como um delimitador, como ponto ;e vírgula, em vez de dois pontos :, será interpretado de maneira diferente, se não for citado. Claro que é um comportamento lógico, mas ainda gosto de confiar na memória muscular. Não gosto de citar o delimitador uma vez, mas não na outra. Apenas preferência pessoal, como eu disse antes: mais fácil de lembrar.
Anne van Rossum 07/10
o período que faz parte do .*é necessário, funcionou bem para mim: cat filename | grep 'Return only this line xyz text' | grep -o 'xyz.*' retornosxyz text
ron
4

Eu costumava ifconfig | grep eth0 | cut -f3- -d:levar isso

    [root@MyPC ~]# ifconfig
    eth0  Link encap:Ethernet  HWaddr AC:B4:CA:DD:E6:F8
          inet addr:192.168.0.2  Bcast:192.168.0.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:78998810244 errors:1 dropped:0 overruns:0 frame:1
          TX packets:20113430261 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:110947036025418 (100.9 TiB)  TX bytes:15010653222322 (13.6 TiB)

e torná-lo assim

    [root@MyPC ~]# ifconfig | grep eth0 | cut -f3- -d:
    C4:7A:4D:F6:B8
Luis Perez
fonte
2
Isso responde a pergunta?
Stephen Rauch
1
Você pode usar cat /sys/class/net/*/address, sem necessidade de análise.
Anne van Rossum
1

No entanto, outra ferramenta canônica que você considerou awkpoderia ser usada com a seguinte linha:

awk -F"stalled" '/stalled/{print $2}' messages

Explicação detalhada:

  • -Fdefine um separador para a linha, ou seja, "parado". Tudo antes do separador é tratado $1e tudo depois com$2 .
  • /reg-ex/ Procura a expressão regular correspondente, neste caso "paralisada".
  • {print $<n>}- imprime n coluna. Como seu separador é definido como paralisado, tudo depois de paralisado é considerado a segunda coluna.
robertm.tum
fonte