bash: print stderr na cor vermelha

103

Existe uma maneira de fazer o bash exibir stderr mensagens na cor vermelha?

    
por kolypto 26.08.2009 / 23:10

11 respostas

85
command 2> >(while read line; do echo -e "\e[01;31m$line\e[0m" >&2; done)
    
por 26.08.2009 / 23:39
75

Método 1: usar a substituição do processo:

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

Método 2: Crie uma função em um script bash:

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

Use assim:

$ color command

Ambos os métodos mostrarão o comando stderr em vermelho.

Continue lendo para uma explicação de como o método 2 funciona. Existem algumas características interessantes demonstradas por este comando.

  • color()... - Cria uma função bash chamada color.
  • set -o pipefail - Esta é uma opção de shell que preserva o código de retorno de erro de um comando cuja saída é canalizada para outro comando. Isso é feito em um subshell, que é criado pelos parênteses, para não alterar a opção pipefail no shell externo.
  • "$@" - Executa os argumentos para a função como um novo comando. "$@" é equivalente a "$1" "$2" ...
  • 2>&1 - Redireciona o stderr do comando para stdout , de modo que se torne sed stdin .
  • >&3 - Abreviação de 1>&3 , isso redireciona stdout para um novo descritor de arquivo temporário 3 . 3 é roteado de volta para stdout depois.
  • sed ... - Devido aos redirecionamentos acima, sed ' stdin é o stderr do comando executado. Sua função é envolver cada linha com códigos de cores.
  • $'...' Uma construção bash que faz com que ela compreenda caracteres com escape de barra invertida
  • .* - corresponde à linha inteira.
  • \e[31m - A sequência de escape ANSI que faz com que os seguintes caracteres sejam vermelhos
  • & - O caractere de substituição sed que se expande para toda a string correspondente (a linha inteira neste caso).
  • \e[m - A sequência de escape ANSI que redefine a cor.
  • >&2 - Abreviação de 1>&2 , isso redireciona sed stdout para stderr .
  • 3>&1 - Redireciona o descritor de arquivo temporário 3 de volta para stdout .
por 23.04.2013 / 22:53
23

Você também pode conferir o stderred: link

    
por 13.12.2011 / 22:40
14

link

    
por 26.08.2009 / 23:18
11

A maneira básica de tornar stderr permanentemente vermelho é usar 'exec' para redirecionar fluxos. Adicione o seguinte ao seu bashrc:

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

Eu já postei sobre isso anteriormente: Como definir a cor da fonte para STDOUT e STDERR

    
por 29.01.2014 / 09:49
7

Eu fiz um script wrapper que implementa a resposta de Balázs Pozsár em puro bash. Salve em seus comandos $ PATH e prefix para colorir sua saída.


    #!/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)

    # Execute command
    "$@" 2> >(while read line; do echo -e "\e[01;31m$line\e[0m" | tee --append $TMP_ERRS; done)
    EXIT_CODE=$?

    # Display all errors again
    if [ -s "$TMP_ERRS" ] ; then
        echo -e "\n\n\n\e[01;31m === ERRORS === \e[0m"
        cat $TMP_ERRS
        fi
    rm -f $TMP_ERRS

    # Finish
    exit $EXIT_CODE

    
por 27.08.2009 / 00:13
3

Você pode usar uma função como esta


 #!/bin/sh

color() {
      printf '3[%sm%s3[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

Eu adiciono > & 2 para imprimir em stderr

    
por 27.08.2009 / 00:29
1

Eu tenho uma versão ligeiramente modificada do script do O_o Tync. Eu precisava fazer esses mods para o OS X Lion e não é perfeito porque o script às vezes é concluído antes do comando wrapped. Eu adicionei um sono, mas tenho certeza que há uma maneira melhor.

#!/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
    
por 08.06.2012 / 19:37
1

Esta solução funcionou para mim: link

Eu coloquei esta função no meu .bashrc ou .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$(echo -en \033)[0m/") 3>&1 1>&2 2>&3
}

Então, por exemplo:

$ rse cat non_existing_file.txt

me dará uma saída em vermelho.

    
por 25.08.2016 / 11:16
0

uma versão usando fifos

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
    
por 04.06.2017 / 12:04
0

usando xargs e printf:

command 2> >(xargs -0 printf "\e[31m%s\e[m" >&2)
    
por 23.08.2018 / 15:37