Como posso personalizar a cor das mensagens de erro no Bash?

7

É possível personalizar os atributos das mensagens de erro do Bash?

Por exemplo, é possível editar o .bash_profile para obter a seguinte mensagem de erro Bash

-bash: cd: foo: No such file or directory

em vermelho?

    
por htaidirt 26.01.2013 / 09:23

5 respostas

2

Infelizmente, não há uma variável de prompt PS para controlar como os erros do bash são apresentados.

stderred é uma solução abrangente para esse tipo de problema, mas não funcionará sem modificações, pois tem uma exclusão codificada para bash (leia mais por boas razões porque). Também é um pouco intrusivo (injeção de DLL).

hilite requer que você o use como wrapper, isso não funcionará para comandos embutidos como cd .

Sua pergunta é feita especificamente sobre as mensagens de erro do bash, estas são enviadas para stderr , mas stderr também é compartilhado com qualquer processo filho, ou seja, com qualquer outro comando. Não tenho certeza se você quer distinguir os dois.

Um problema oculto aqui é que bash escreve o prompt e sua entrada (echo) para stderr . Para provar:

bash              # start a sacrificial shell
exec 2> tmpfile   # change stderr to a file
ls                # you will see no prompt, and no command echo
... 
exit              # quit sacrificial shell
cat tmpfile       # contains PS1 prompt, your commands (and any errors too)

Builtins chamam (ou pelo menos devem chamar) a função interna builtin_error() para imprimir erros, isso chama incondicionalmente fprintf() to stderr , então as opções são poucas.

Sem saltar por aros ou aplicar patches em bash , uma maneira simples de destacar erros é:

function _t_debug() 
{
    if [ "${BASH_COMMAND:0:6}" != "_t_err" ]; then
        _lastcmd="$BASH_COMMAND"
    fi  
}
function _t_err() 
{
    local rc=$1 nn _type _argv
    #shift; pipe=($*)
    #if [ ${#pipe[*]} -gt 1 ]; then
    #    for ((nn=1; nn<=${#pipe[*]};nn++));do
    #        rc=${pipe[$((nn-1))]}
    #        echo -n "[$nn]=$rc ";
    #        ((rc >=128)) && echo -n "($((rc-128))) "
    #    done
    #fi

    read -a _argv <<< ${_lastcmd}
    _type=$(type -t "${_argv[0]}")

    if [ -n "$_lastcmd" ]; then
        tput setf 4
        printf 'Error %s: "%s"' "${_type}" "${_lastcmd:-unknown command}"
        tput sgr 0
        printf "\n"
    fi

    ((rc >=128)) && echo "[rc=$rc ($((rc-128)))]" ||
    echo "[rc=$rc]"
}
trap '_t_err $? ${PIPESTATUS[*]}' ERR
trap '_t_debug' DEBUG

Isso usa o bash DEBUG trap para armazenar em cache cada linha de comando antes da execução e a ERR trap para gerar os códigos de retorno se não forem zero. Porém, isso não acontecerá com determinados comandos internos (especificamente comandos compostos : while/case/for/if e mais, veja a página man).

Eu uso uma variação disso no meu .profile , embora eu use o pipe[]/PIPESTATUS[] bit comentado acima, não é compatível com uma armadilha DEBUG como apresentado acima. Se você comentar o trap DEBUG , poderá usá-lo para mostrar o código de retorno de cada comando em um pipeline.

(Além disso, como é referenciado, o gancho da função command_not_found é bash-4.0 +.)

    
por 28.01.2013 / 16:08
2

Você pode querer conferir stderrred para uma solução mais permanente.

    
por 26.01.2013 / 12:59
1

Abaixo, a solução funciona para o que você deseja:

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

Basicamente, o comando acima imprime stderr em vermelho.

Verifique abaixo a captura de tela:

Eu não sei como tornar isso permanente. No entanto, isso deve definitivamente dar algumas dicas.

    
por 26.01.2013 / 11:00
0

Talvez você possa tentar hilite - acho que essa é uma das soluções mais simples.

    
por 26.01.2013 / 16:40
0

Coloque isso no seu arquivo ~/.bashrc ou ~/.bash_profile para uma correção permanente ou, se você quiser que seja temporário, apenas digite isso em bash .

command_not_found_handle () { 
  tput bold;
  tput setaf 1;
  echo "$0: $1: command not found"; 
  tput sgr0; 
}

Ele fará com que bash imprima o comando que não encontrou o erro em negrito e vermelho. Vá em frente e retire tput bold; para que a mensagem de erro não fique em negrito ou altere o tput setaf 1 para outro número para uma cor diferente. Espero que ajude !!

EDITAR

Aqui está uma versão nova e melhorada do acima:

command_not_found_handle () {
  echo -e "\e[1;31m$0: $1: command not found\e[0;0m";
  return 127; #return bash's error code for command not found
}

EDIT 2

If the name is neither a shell function nor a builtin, and contains no slashes, bash
searches each element of the PATH for a directory containing an executable file by that
name. Bash uses a hash table to remember the full pathnames of executable files (see hash
under SHELL BUILTIN COMMANDS below). A full search of the directories in PATH is performed
only if the command is not found in the hash table. If the search is unsuccessful, the
shell searches for a defined shell function named command_not_found_handle. If that
function exists, it is invoked with the original command and the original command's
arguments as its arguments, and the function's exit status becomes the exit status of the
shell. If that function is not defined, the shell prints an error message and returns an
exit status of 127.

Extraído de página do bash

Portanto, se isso não funcionar, talvez seu shell não seja verdadeiro bash ou seja uma versão modificada de bash .

    
por 26.01.2013 / 14:31

Tags