Redirecionando a saída dependendo do grep regex

8

Estou usando gradle runpara iniciar um servidor REST. A saída do servidor REST é semelhante a esta:

XXX.XXX.XX.XXX - <moreinfo>
randomtext
randomtext
XXX.XXX.XX.XXX - <moreinfo>
XXX.XXX.XX.XXX - <moreinfo>
randomtext
XXX.XXX.XX.XXX - <moreinfo>

XXX.XXX.XX.XXXaqui está um endereço IP, texto aleatório são mensagens de erro. Toda saída é direcionada para stdout, infelizmente.

Como direcionar todas as linhas que começam com um endereço IP para um arquivo chamado err.loge todas as outras linhas para all.log?

Infelizmente, gradle runsó pode ser iniciado uma vez e não para, pois é um servidor REST.

Talvez usar uma tee, grepcombinação?

polym
fonte

Respostas:

8

No Bash, você pode usar a substituição de processo com tee:

tee >(grep XXX > err.log) | grep -v XXX > all.log

Isso colocará todas as linhas correspondentes a XXX err.loge todas as linhas all.log. >( ... )cria o processo entre parênteses e conecta sua saída padrão a um tubo. Isso funciona no zsh e em outras conchas modernas também.

Você também pode usar o peecomando de moreutils :

pee "grep XXX > err.log" "grep -v XXX > all.log"

pee redireciona a entrada padrão para vários comandos ("tee para pipes").

Uma outra alternativa é com o awk:

awk '{ if (/^([0-9]{1,3}\.){3}[0-9]{1,3}/) { print > "err.log" } else { print > "all.log" } }'

Isso apenas testa todas as linhas em relação à expressão e grava a coisa toda err.logse ela corresponder e all.logse não corresponder.

A expressão regular awk também é adequada grep -E(embora corresponda a alguns endereços incorretos - 999.0.0.0e assim por diante - mas isso provavelmente não é um problema).

Michael Homer
fonte
Hmm err.logestá vazio e toda a saída é redirecionada para o all.loguso do teecomando acima.
Polym
Verifique se sua expressão regular está realmente correspondendo às linhas corretas - se err.logexistir, o comando foi executado, mas nada saiu. grep -Ecom a expressão usada no comando awk deve corresponder, ou aqui.
Michael Homer
Ah, ok, entendi. Você pode modificar sua pergunta para que all.lognão contenha as linhas correspondentes na expressão grep?
Polym
Feito - não tinha certeza de qual você queria, então eu tive os dois.
Michael Homer
Oh, desculpe, funcionou. Eu substituí all.loge err.logcom um comando antigo. Desculpe pela confusão. Obrigado, você é incrível :)) !!
Polym
4

Assim, parece que gradle runnão cumpra tee, pee, grepe io-redirecionamento. Ele sempre para de ler após 4096 bytes.

Para contornar esse problema, eu readcada linha de gradle run. Ainda não testei, mas acho que a leitura de uma linha com mais de 4k caracteres também falhará.

De qualquer forma, aqui está o código para resolver minha pergunta especificamente:

#!/bin/bash
STDOUTLOG="/log/stdout.txt"
STDERRLOG="/log/stderr.txt"
while read -r line; do
    [[ $line =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}.* ]] && printf '%s\n' "$line" >> "$STDERRLOG" && continue
    printf '%s\n' "$line" >> "$STDOUTLOG"
done < <(gradle run)
polym
fonte
1
Você deve usar read -r linee printf '%s\n' "$line"para evitar alguns ponta casos quebrando coisas.
precisa saber é o seguinte
@ nyuszika7h Obrigado! Eu modifiquei a resposta em conformidade :).
polym