Pregunta bash: impresión stderr en color rojo


¿Hay alguna manera de hacer una pantalla de bash? Stderr mensajes en color rojo?


97
2017-08-26 21:10


origen


Supongo que bash nunca coloreará su salida: algunos programas pueden querer analizar algo, y el colorear echará a perder los datos con secuencias escapadas. Una aplicación GUI debería manejar los colores, supongo. - kolypto
La combinación de la respuesta de Balázs Pozsár y killdash9 da lo mejor: function color { "$@" 2> >(sed $'s,.*,\e[31m&\e[m,') }  Trabaja para bash y zsh. No se puede agregar esto como una reputación b / c reputación. - Heinrich Hartmann
Estoy esperando una respuesta que modifique a bash para hacer esto. Las soluciones por debajo de todo. actualmente modificar stderr y posiblemente incluso reordenar w.r.t. stdout que rompe cosas cuando la secuencia exacta de bytes de stderr debe conservarse, por ejemplo. cuando la tubería. - masterxilo


Respuestas:


command 2> >(while read line; do echo -e "\e[01;31m$line\e[0m" >&2; done)

84
2017-08-26 21:39



¡Genial! Pero me pregunto si hay una manera de hacerlo permanente :) - kolypto
Gran consejo Sugerencia: Añadiendo >&2 justo antes de ; done), la salida prevista para stderr en realidad se escribe en stderr. Eso es útil si desea capturar la salida normal del programa. - henko
Los siguientes usos. tput, y es un poco más legible en mi opinión: command 2> >(while read line; do echo -e "$(tput setaf 1)$line$(tput sgr0)" >&2; done) - Stefan Lasiewski
Creo que la ejecución de 2 procesos tput para cada línea de salida no es nada elegante. Tal vez si almacena la salida de los comandos tput en una variable y los utiliza para cada eco. Pero, de nuevo, la legibilidad no es realmente mejor. - Balázs Pozsár
Esta solución no conserva los espacios en blanco, pero me gusta por su brevedad. IFS= read -r line debería ayudar pero no lo hace. No estoy seguro de por qué. - Max Murphy


Método 1: uso de sustitución de proceso:

command 2> >(sed $'s,.*,\e[31m&\e[m,'>&2)

Método 2: crear una función en un script bash:

color()(set -o pipefail;"$@" 2>&1>&3|sed $'s,.*,\e[31m&\e[m,'>&2)3>&1

Úsalo así:

$ color command

Ambos métodos mostrarán el comando stderr en rojo.

Sigue leyendo para obtener una explicación de cómo funciona el método 2. Hay algunas características interesantes demostradas por este comando.

  • color()... - Crea una función bash llamada color.
  • set -o pipefail - Esta es una opción de shell que conserva el código de retorno de error de un comando cuya salida se canaliza a otro comando. Esto se hace en una subshell, que es creada por los paréntesis, para no cambiar la opción pipefail en el shell externo.
  • "$@" - Ejecuta los argumentos de la función como un nuevo comando. "$@" es equivalente a "$1" "$2" ...
  • 2>&1 - Redirige el stderr del comando para stdout para que se convierta sedes stdin.
  • >&3 - taquigrafía para 1>&3, esto redirige stdout a un nuevo descriptor de archivo temporal 3. 3 se enruta de nuevo en stdout luego.
  • sed ... - Debido a las redirecciones anteriores, sedes stdin es el stderr de la orden ejecutada. Su función es rodear cada línea con códigos de color.
  • $'...' Una construcción de bash que hace que comprenda los caracteres escapados de barra invertida
  • .* - Coincide con toda la línea.
  • \e[31m - La secuencia de escape ANSI que hace que los siguientes caracteres sean rojos.
  • & - Los sed Reemplace el carácter que se expande a toda la cadena coincidente (la línea completa en este caso).
  • \e[m - La secuencia de escape ANSI que restablece el color.
  • >&2 - taquigrafía para 1>&2, esto redirige sedes stdout a stderr.
  • 3>&1 - Redirige el descriptor de archivo temporal 3 de vuelta en stdout.

72
2018-04-23 20:53



+1 mejor respuesta! Absolutamente subestimado! - muhqu
Gran respuesta y aún mejor explicación. - Daniel Serodio
¿Por qué necesitas hacer toda la redirección adicional? parece una exageración - qodeninja
@qodeninja La explicación da el propósito para la redirección. Si puedes encontrar una forma más sencilla de hacerlo, ¡me encantaría verlo! - killdash9
¿Hay alguna manera de hacerlo funcionar en zsh? - Eyal Levin


También puedes echar un vistazo a stderred: https://github.com/sickill/stderred


23
2017-12-13 21:40



Wow, esta utilidad es excelente, lo único que necesitaría es tener un repositorio de apt que lo instale para todos los usuarios, con una línea, sin tener que hacer más trabajo para habilitarlo. - sorin
Parecía funcionar bien cuando lo probé con un script de compilación en un terminal separado, pero no me atrevo a usarlo globalmente (en .bashrc). Gracias aunque! - Joel Purra
En OS X El Capitan, la forma en que funciona (DYLD_INSERT_LIBRARIES) está "dañada" en los binarios del sistema porque están protegidos por SIP. Por lo tanto, podría ser mejor usar las opciones de bash dadas en otras respuestas. - hmijail
@hmijail para MacOS por favor siga github.com/sickill/stderred/issues/60 así que podemos encontrar una solución, una parcial ya existe pero está un poco llena de errores. - sorin


http://sourceforge.net/projects/hilite/


14
2017-08-26 21:18





La forma de hacer bash Stderr permanentemente rojo está usando 'exec' para redirigir los flujos. Agregue lo siguiente a su bashrc:

exec 9>&2
exec 8> >(
    while IFS='' read -r line || [ -n "$line" ]; do
       echo -e "\033[31m${line}\033[0m"
    done
)
function undirect(){ exec 2>&9; }
function redirect(){ exec 2>&8; }
trap "redirect;" DEBUG
PROMPT_COMMAND='undirect;'

He publicado en esto anteriormente: Cómo establecer el color de fuente para STDOUT y STDERR


11
2018-01-29 08:49



relacionado: unix.stackexchange.com/questions/367636/… - Blauhirn
Esta es la mejor respuesta con diferencia; fácil de implementar sin necesidad de instalar / requerir sudo privilegio, y se puede generalizar a todos los comandos. - Luke Davis
Desafortunadamente, esto no funciona bien con el encadenamiento de comandos (comando && nextCommand || errorHandlerCommand). La salida de error va después de la salida errorHandlerCommand. - carlin.scott
Del mismo modo, si yo source ~/.bashrc dos veces con esto, mi terminal básicamente se bloquea. - Dolph
@Dolf: En mi bashrc me protejo fácilmente contra esto con una declaración if que lo rodea para evitar que este código se vuelva a cargar. De lo contrario, el problema es la redirección 'exec 9> & 2' después de que la redirección ya haya tenido lugar. Tal vez cámbielo a una constante si sabe a donde> 2 está apuntando originalmente. - gospes


He hecho un script de envoltorio que implementa la respuesta de Balázs Pozsár en puro bash. Guárdelo en sus comandos $ PATH y prefix para colorear su salida.


    #! / bin / bash

    si [$ 1 == "--help"]; entonces
        echo "Ejecuta un comando y colorea todos los errores ocurridos"
        echo "Ejemplo:` nombre base $ {0} `wget ..."
        echo "(c) o_O Tync, ICQ # 1227-700, ¡Disfruta!"
        salida 0
        fi

    # Temp archivo para atrapar todos los errores
    TMP_ERRS = $ (mktemp)

    # Ejecutar comando
    "$ @" 2>> (mientras se lee la línea; haga eco -e "\ e [01; 31m $ línea \ e [0m" | tee --append $ TMP_ERRS; listo)
    EXIT_CODE = $?

    # Mostrar todos los errores de nuevo
    si [-s "$ TMP_ERRS"]; entonces
        echo -e "\ n \ n \ n \ e [01; 31m === ERRORES === \ e [0m"
        cat $ TMP_ERRS
        fi
    rm -f $ TMP_ERRS

    # Terminar
    salir $ EXIT_CODE


7
2017-08-26 22:13



Esto podría hacerse más eficiente si "| tee ..." se pusiera después de "done". - Juliano


Puedes usar una función como esta


 #!/bin/sh

color() {
      printf '\033[%sm%s\033[m\n' "$@"
      # usage color "31;5" "string"
      # 0 default
      # 5 blink, 1 strong, 4 underlined
      # fg: 31 red,  32 green, 33 yellow, 34 blue, 35 purple, 36 cyan, 37 white
      # bg: 40 black, 41 red, 44 blue, 45 purple
      }
string="Hello world!"
color '31;1' "$string" >&2


3
2017-08-26 22:29



No abordando el problema. No ha proporcionado una forma de separar stderr de stdout, que es lo que le interesa a la O.P. - Jeremy Visser


Tengo una versión ligeramente modificada de la secuencia de comandos de O_o Tync. Necesitaba hacer estos mods para OS X Lion y no es perfecto porque el script a veces se completa antes que el comando envuelto. He añadido un sueño pero estoy seguro de que hay una mejor manera.

#!/bin/bash

   if [ $1 == "--help" ] ; then
       echo "Executes a command and colorizes all errors occured"
       echo "Example: `basename ${0}` wget ..."
       echo "(c) o_O Tync, ICQ# 1227-700, Enjoy!"
       exit 0
       fi

   # Temp file to catch all errors
   TMP_ERRS=`mktemp /tmp/temperr.XXXXXX` || exit 1

   # Execute command
   "$@" 2> >(while read line; do echo -e "$(tput setaf 1)$line\n" | tee -a $TMP_ERRS; done)
   EXIT_CODE=$?

   sleep 1
   # Display all errors again
   if [ -s "$TMP_ERRS" ] ; then
       echo -e "\n\n\n$(tput setaf 1) === ERRORS === "
       cat $TMP_ERRS
   else
       echo "No errors collected in $TMP_ERRS"
   fi
   rm -f $TMP_ERRS

   # Finish
   exit $EXIT_CODE

1
2018-06-08 17:37





Esta solución funcionó para mí: https://superuser.com/questions/28869/immently-tell-which-output-was-sent-to-stderr

He puesto esta función en mi .bashrc o .zshrc:

# Red STDERR
# rse <command string>
function rse()
{
    # We need to wrap each phrase of the command in quotes to preserve arguments that contain whitespace
    # Execute the command, swap STDOUT and STDERR, colour STDOUT, swap back
    ((eval $(for phrase in "$@"; do echo -n "'$phrase' "; done)) 3>&1 1>&2 2>&3 | sed -e "s/^\(.*\)$/$(echo -en \\033)[31;1m\1$(echo -en \\033)[0m/") 3>&1 1>&2 2>&3
}

Entonces, por ejemplo:

$ rse cat non_existing_file.txt

Me dará una salida roja.


1
2017-08-25 09:16





una versión usando quince

mkfifo errs
stdbuf -o0 -e0 -i0 grep . foo | while read line; do echo -e "\e[01;31m$line  \e[0m" >&2; done &
stdbuf -o0 -e0 -i0 sh $script 2>errs

0
2018-06-04 10:04