Comment définir la couleur de la police pour STDOUT et STDERR

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 le différencier en couleurs; c’est possible?

(Par exemple, la couleur de la police stderr est rouge et la couleur de la police stdout est bleue).

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:

Compte tenu des 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 la police de votre terminal sur rouge (par défaut, qui sera utilisée pour stderr). Ensuite, exécutez votre commande et dirigez la formatOutput standard via formatOutput définie ci-dessus (qui imprime simplement chaque ligne en bleu et réinitialise la couleur de la police en rouge):

 shell$ red shell$ ls / somenonexistingfile | formatOutput 

La commande ci-dessus imprimera à la fois stderr et stdout et vous verrez que les lignes sont colorées différemment.

J’espère que cela t’aides


METTRE À JOUR:

Pour rendre cela réutilisable, j’ai tout mis 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 

Il montrera le stderr la commande en rouge.

Continuez à lire pour une explication de son fonctionnement. Il y a quelques fonctionnalités intéressantes démontrées par cette commande.

  • color()... – Crée une fonction bash appelée color.
  • set -o pipefail – C’est une option shell qui préserve le code retour d’erreur d’une commande dont la sortie est redirigée vers une autre commande. Cela se fait dans un sous-shell, qui est créé par les parenthèses, afin de ne pas modifier 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 vers stdout pour qu’il devienne stdin .
  • >&3 – Abréviation de 1>&3 , redirige stdout vers un nouveau descripteur de fichier temporaire 3 . 3 est renvoyé dans stdout plus tard.
  • sed ... – En raison des redirections ci-dessus, stdin sed est le stderr de la commande exécutée. Sa fonction est d’entourer chaque ligne avec des codes de couleur.
  • $'...' Une construction bash qui lui permet de comprendre les caractères d’échappement antislash
  • .* – Correspond à toute la ligne.
  • \e[31m – La séquence d’échappement ANSI qui fait apparaître les caractères suivants en rouge
  • & – Le caractère sed replace qui s’étend à la chaîne entière correspondante (la ligne entière dans ce cas).
  • \e[m – La séquence d’échappement ANSI qui réinitialise la couleur.
  • >&2 – raccourci pour 1>&2 , cela redirige la sed stdout sed vers stderr .
  • 3>&1 : redirige le descripteur de fichier temporaire 3 dans stdout .

Je colore stderr red en liant le descripteur de fichier à une fonction personnalisée qui ajoute de la couleur à tout ce qui passe à travers. Ajoutez à la suite à 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? Le piège de débogage est exécuté 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 soit affichée et avec cela, je restaure l’état normal de stderr . Cela est nécessaire car PS1 et PS2 (votre invite) sont imprimés sur stderr et je ne souhaite pas d’invite rouge. voila, sortie rouge sur stderr !

Vous devriez vérifier stderred: https://github.com/sickill/stderred

Oui, ce n’est pas possible en mode natif. Vous devrez pirater la gestion de tty (dans le kernel).

J’ai fini en quelque sorte un petit wrapper C avant de voir les autres réponses 🙂 Peut-être bogué, et les valeurs sont codées en dur, ne l’utilisez pas sauf pour les tests.

 #include "unistd.h" #include "stdio.h" #include  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 de tty.) Frapper ^ C n'affichera pas un message d'erreur moche, et il se comporte correctement sur cet exemple:

 ./c_color_script sh -c "while true; do (echo -na; echo -nb 1>&2) done" 

Je suis surpris que personne n’ait réellement compris comment colorer les stream stdio. Cela va colorer stderr rouge pour tout le (sous) shell:

 exec 3>&2 exec 2> >(sed -u 's/^\(.*\)$/'$'\e''[31m\1'$'\e''[m/' >&3) 

Dans ce cas, &3 contiendra le stream stderr d’origine.

Vous ne devriez pas passer de commandes à exec , seulement les redirections. Dans ce cas particulier, exec remplace les stream stdio du (sous) shell actuel par ceux qu’il reçoit.

Il y a quelques réserves:

  • Puisque sed s’exécutera de manière persistante dans un sous-shell parallèle, toute sortie directe immédiatement après une écriture sur le stdio coloré sera probablement battue par sed au tty .
  • Cette méthode utilise un descripteur de fichier FIFO; Les nœuds FIFO ne traitent que des lignes. Si vous n’écrivez pas un saut de ligne dans le stream, votre sortie sera mise en mémoire tampon jusqu’à ce qu’une nouvelle ligne soit détectée. Cela ne met pas en mémoire tampon la partie sed : c’est la manière dont fonctionnent ces types de fichiers.

La plus compliquée des mises en garde est la première, mais une condition de concurrence 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 uniques en passant par la même commande sed avec l’opérateur de pipeline normal ( | ). Les chaînes canalisées sont exécutées de manière synchrone, de sorte qu’aucune condition de concurrence ne se produira, bien que la dernière commande dans une chaîne de production reçoive son propre sous-shell par défaut.