Je souhaite différencier les messages STDOUT et STDERR dans mon terminal. Si un script ou une commande imprime un message dans le terminal, je souhaite différencier par des couleurs; c'est possible?
(Par exemple, la couleur de la police stderr est le rouge et la couleur de la police stdout est le bleu.)
Exemple (en gras):
$date
Wed Jul 27 12:36:50 IST 2011
$datee
bash: datee: command not found
$alias ls
alias ls='ls --color=auto -F'
$aliass ls
bash: aliass: command not found
Voici un hack auquel j'ai pensé et qui semble fonctionner:
Étant donné les alias suivants pour la lisibilité:
alias blue='echo -en "\033[36m"'
alias red='echo -en "\033[31m"'
alias formatOutput='while read line; do blue; echo $line; red; done'
Maintenant, vous devez d'abord définir la couleur de police de votre terminal sur rouge (comme valeur par défaut, elle sera utilisée pour stderr). Ensuite, exécutez votre commande et dirigez la sortie standard vers formatOutput
défini chaque ligne en bleu puis réinitialise la couleur de la police en rouge):
Shell$ red
Shell$ ls / somenonexistingfile | formatOutput
La commande ci-dessus imprimera à la fois dans stderr et stdout et vous verrez que les lignes sont colorées différemment.
J'espère que cela t'aides
METTRE À JOUR:
Pour que cela soit réutilisable, j'ai tout écrit dans un petit script:
$ cat bin/run
#!/bin/bash
echo -en "\033[31m" ## red
eval $* | while read line; do
echo -en "\033[36m" ## blue
echo $line
echo -en "\033[31m" ## red
done
echo -en "\033[0m" ## reset color
Maintenant, vous pouvez l'utiliser avec n'importe quelle commande:
$ run yourCommand
Créez une fonction dans un shell ou un script bash:
color()(set -o pipefail;"$@" 2>&1>&3|sed $'s,.*,\e[31m&\e[m,'>&2)3>&1
Utilisez-le comme ceci:
$ color command -program -args
La commande affiche stderr
en rouge.
Continuez votre lecture pour une explication de la façon dont cela fonctionne. Certaines fonctions intéressantes sont illustrées par cette commande.
color()...
- Crée une fonction bash appelée couleur.set -o pipefail
- Ceci est une option du shell qui conserve le code de retour d'erreur d'une commande dont la sortie est acheminée dans une autre commande. Ceci est fait dans un sous-shell, qui est créé par les parenthèses, afin de ne pas changer l'option pipefail dans le shell externe. "$@"
- Exécute les arguments de la fonction en tant que nouvelle commande. "$@"
est équivalent à "$1" "$2" ...
2>&1
- Redirige le stderr
de la commande en stdout
afin qu'il devienne sed
name __ 's stdin
name__.>&3
- Abrégé pour 1>&3
, ceci redirige stdout
vers un nouveau descripteur de fichier temporaire 3
. 3
est redirigé dans stdout
plus tard.sed ...
- En raison des redirections ci-dessus, sed
name __ 's stdin
est le stderr
de la commande exécutée. Sa fonction est d’entourer chaque ligne de codes de couleur.$'...'
Une construction bash qui lui permet de comprendre les caractères échappés par une barre oblique inverse.*
- Correspond à la ligne entière.\e[31m
- La séquence d'échappement ANSI qui fait apparaître les caractères suivants en rouge&
- Le caractère sed
qui remplace la chaîne correspondante (la ligne entière dans ce cas).\e[m
- La séquence d'échappement ANSI qui réinitialise la couleur.>&2
- Abrégé pour 1>&2
, ceci redirige sed
name __ 's stdout
en stderr
name__.3>&1
- Réoriente le descripteur de fichier temporaire 3
dans stdout
name__.Je couleur stderr red en liant le descripteur de fichier à une fonction personnalisée qui ajoute de la couleur à tout ce qui la traverse. Ajouter à la suite de votre .bashrc
:
export COLOR_RED="$(tput setaf 1)"
export COLOR_RESET="$(tput sgr0)"
exec 9>&2
exec 8> >(
Perl -e '$|=1; while(sysread STDIN,$a,9999) {print
"$ENV{COLOR_RED}$a$ENV{COLOR_RESET}"}'
)
function undirect(){ exec 2>&9; }
function redirect(){ exec 2>&8; }
trap "redirect;" DEBUG
Prompt_COMMAND='undirect;'
Alors qu'est-ce qui se passe? L'interruption de débogage est exécutée juste avant et immédiatement après l'exécution d'une commande. stderr est donc redirigé avant l'exécution d'une commande pour activer la sortie rouge. Prompt_COMMAND est évalué avant que l'invite ne s'affiche et, avec cela, je restaure stderr à son état normal. Cela est nécessaire car PS1 et PS2 (votre invite) sont imprimés sur stderr et je ne souhaite pas d'invite rouge. le tour est joué, sortie rouge sur stderr !
Vous devriez vérifier stderred: https://github.com/sickill/stderred
Oui ce n'est pas possible nativement. Vous devrez pirater la gestion de tty (dans le noyau).
J'ai en quelque sorte fini une petite enveloppe C avant d'avoir vu les autres réponses: -) Peut-être un bug, et les valeurs sont codées en dur, ne l'utilisez pas sauf pour les tests.
#include "unistd.h"
#include "stdio.h"
#include <sys/select.h>
int main(int argc, char **argv)
{
char buf[1024];
int pout[2], perr[2];
pipe(pout); pipe(perr);
if (fork()!=0)
{
close(1); close(2);
dup2(pout[1],1); dup2(perr[1],2);
close(pout[1]); close(perr[1]);
execvp(argv[1], argv+1);
fprintf(stderr,"exec failed\n");
return 0;
}
close(pout[1]); close(perr[1]);
while (1)
{
fd_set fds;
FD_ZERO(&fds);
FD_SET(pout[0], &fds);
FD_SET(perr[0], &fds);
int max = pout[0] > perr[0] ? pout[0] : perr[0];
int v = select(max+1, &fds, NULL, NULL, NULL);
if (FD_ISSET(pout[0], &fds))
{
int r;
r = read(pout[0], buf, 1024);
if (!r) {close(pout[0]); continue;}
write(1, "\033[33m", 5);
write(1, buf, r);
write(1, "\033[0m", 4);
}
if (FD_ISSET(perr[0], &fds))
{
int r;
r = read(perr[0], buf, 1024);
if (!r) {close(perr[0]); continue;}
write(2, "\033[31m", 5);
write(2, buf, r);
write(2, "\033[0m", 4);
}
if (v <= 0) break;
}
return 0;
}
Edit: Comparé à la solution Shell, celui-ci conservera plus souvent l’ordre des lignes/caractères. (Il n'est pas possible d'être aussi précis que la lecture directe d'un tty.) Frapper ^ C ne montrera pas un message d'erreur laid, et il se comporte correctement sur cet exemple:
./c_color_script sh -c "while true; do (echo -n a; echo -n b 1>&2) done"
Je suis surpris que personne n'ait vraiment compris comment colorer les flux stdio. Cela colorera stderr red pour l’ensemble du (sous) Shell:
exec 3>&2
exec 2> >(sed -u 's/^\(.*\)$/'$'\e''[31m\1'$'\e''[m/' >&3)
Dans ce cas, &3
contiendra le flux stderr d'origine.
Vous ne devez transmettre aucune commande à exec
, mais uniquement aux redirections. Dans ce cas particulier, exec
remplace les flux stdio du (sous) Shell actuel par ceux qu’il reçoit.
Il y a quelques mises en garde:
sed
fonctionnera de manière persistante dans un sous-shell parallèle, toute sortie directe qui suivra immédiatement une écriture sur le stodo coloré sera probablement supérieure à sed
à tty
.sed
: c'est comment fonctionnent ces types de fichiers.Le plus gênant des avertissements est le premier, mais une condition de concurrence critique peut être plus ou moins évitée en appliquant un traitement similaire à toutes les sorties, même si vous utilisez la couleur par défaut.
Vous pouvez effectuer un traitement similaire pour des commandes simples en créant un lien vers la même commande sed
avec l'opérateur de canal normal (|
). Les chaînes distribuées étant exécutées de manière synchrone, aucune situation de concurrence critique ne se produira, bien que la dernière commande d'une chaîne de distribution reçoive son propre sous-shell par défaut.
En développant la réponse donnée par @gospes, j'ai ajouté la fonctionnalité permettant d'imprimer des lignes partielles sans attendre une nouvelle ligne et quelques commentaires. Permet une meilleure sortie de wget ou de la saisie dans un shell interactif.
exec 9>&2
exec 8> >(
while [ "$r" != "1" ]; do
# read input, no field separators or backslash escaping, 1/20th second timeout
IFS='' read -rt 0.05 line
r=$?
# if we have input, print the color change control char and what input we have
if ! [ "${#line}" = "0" ]; then
echo -ne "\e[1;33m${line}"
fi
# end of line detected, print default color control char and newline
if [ "$r" = "0" ] ; then
echo -e "\e[0m"
fi
# slow infinite loops on unexpected returns - shouldn't happen
if ! [ "$r" = "0" ] && ! [ "$r" = "142" ]; then
sleep 0.05
fi
done
)
function undirect(){ exec 2>&9; }
function redirect(){ exec 2>&8; }
trap "redirect;" DEBUG
Prompt_COMMAND='undirect;'
J'ai utilisé le jaune vif (1; 33) mais vous pouvez le remplacer par n'importe quoi, rouge par exemple (31) ou rouge vif (1; 33), et j'ai choisi arbitrairement 0,05 seconde pour une nouvelle vérification de fin de ligne et de pause. sur les codes de retour inattendus (jamais trouvé); il pourrait probablement être abaissé ou éventuellement supprimé de la commande de lecture.