command 2> >(while read line; do echo -e "\e[01;31m$line\e[0m" >&2; done)
Existe uma maneira de fazer o bash exibir stderr mensagens na cor vermelha?
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
. Você também pode conferir o stderred: link
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
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
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
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
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.
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
usando xargs e printf:
command 2> >(xargs -0 printf "\e[31m%s\e[m" >&2)