Redirection de la sortie en fonction de l'expression rationnelle grep

8

J'utilise gradle runpour démarrer un serveur REST. La sortie du serveur REST ressemble à ceci:

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.XXXvoici une adresse IP, randomtext sont des messages d'erreur. Malheureusement, toutes les sorties sont dirigées vers la sortie standard.

Comment puis-je diriger toutes les lignes commençant par une adresse IP vers un fichier appelé err.loget toutes les autres lignes vers all.log?

Malheureusement, gradle runne peut être démarré qu'une seule fois et ne s'arrête pas, car il s'agit d'un serveur REST.

Peut - être utiliser une tee, grepcombinaison?

polym
la source

Réponses:

8

Dans Bash, vous pouvez utiliser la substitution de processus avec tee:

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

Cela mettra toutes les lignes correspondant à XXX dans err.log, et toutes les lignes dans all.log. >( ... )crée le processus entre parenthèses et connecte sa sortie standard à un tuyau. Cela fonctionne aussi avec zsh et d'autres shells modernes.

Vous pouvez également utiliser la peecommande de moreutils :

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

pee redirige l'entrée standard vers plusieurs commandes ("tee for pipes").

Une autre alternative est avec awk:

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

Cela teste simplement chaque ligne par rapport à l'expression et écrit le tout err.logsi elle correspond et all.logsi ce n'est pas le cas.

L'expression régulière awk convient grep -Eégalement (bien qu'elle corresponde à de mauvaises adresses - 999.0.0.0et ainsi de suite - mais ce n'est probablement pas un problème).

Michael Homer
la source
Hmm err.logest vide et toutes les sorties sont redirigées vers all.logla teecommande ci-dessus.
polym
Vérifiez que votre expression régulière correspond bien aux bonnes lignes - si elle err.logexiste, alors la commande s'est exécutée mais rien n'est sorti. grep -Eavec l'expression utilisée dans la commande awk doit correspondre, ou c'est le cas ici.
Michael Homer
Ah ok je l'ai. Pouvez-vous modifier votre question afin qu'elle all.logne contienne pas les lignes correspondantes dans l'expression grep?
polym
Terminé - je ne savais pas lequel vous vouliez, alors j'avais les deux.
Michael Homer
Oh sacrément désolé, cela a fonctionné. J'ai écrasé all.loget err.logavec une ancienne commande. Désolé pour la confusion. Merci, tu es génial :)) !!
polym
4

Ainsi , il semble que gradle runne respecte pas tee, pee, grepet io-redirection. Il arrête toujours la lecture après 4096 octets.

Pour contourner ce problème, j'ai readchaque ligne de gradle run. Je ne l'ai pas encore testé, mais je suppose que la lecture d'une ligne de plus de 4 000 caractères échouera également.

Quoi qu'il en soit, voici le code pour résoudre ma question en particulier:

#!/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
la source
1
Vous devez utiliser read -r lineet printf '%s\n' "$line"pour éviter que certains cas de bord ne cassent les choses.
nyuszika7h
@ nyuszika7h Merci! J'ai modifié la réponse en conséquence :).
polym