7

Можно ли настроить атрибуты сообщений об ошибках Bash?

Например, можно ли отредактировать .bash_profile чтобы получить следующее сообщение об ошибке Bash

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

в красном?

5 ответов5

2

Возможно, вы захотите проверить stderrred для более постоянного решения.

2

К сожалению, переменная подсказки PS отсутствует, чтобы управлять отображением ошибок bash.

stderred - это комплексное решение для проблем такого типа, но оно не будет работать без изменений, поскольку в нем есть жестко запрограммированное исключение для bash (см. веские причины, почему это так). Также это несколько навязчиво (внедрение DLL).

hilite требует, чтобы вы использовали его в качестве оболочки, это не будет работать для встроенных команд bash, таких как cd .

Ваш вопрос касается конкретно сообщений об ошибках bash, они отправляются в stderr , но stderr также используется всеми дочерними процессами, то есть любыми другими командами. Я не уверен, если вы хотите различить два.

Скрытая проблема заключается в том, что bash сам записывает приглашение и ваш ввод (echo) в stderr . Чтобы доказать:

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)

Встроенные функции вызывают (или, по крайней мере, должны вызывать) внутреннюю функцию builtin_error() для вывода ошибок, это безусловно вызывает функцию fprintf() для stderr , поэтому вариантов немного.

Без перехода через обручи или исправления bash , простой способ выделения ошибок:

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

При этом используется ловушка bash DEBUG для кэширования каждой командной строки перед выполнением и ловушка ERR для вывода кодов возврата, если они не равны нулю. Однако этого не произойдет для некоторых встроенных команд bash (в частности, составных команд: while/case/for/if и более, см. Справочную страницу).

Я использую вариацию этого в моем .profile , хотя я использую бит pipe[]/PIPESTATUS[] закомментированный выше, он не совместим с ловушкой DEBUG, как представлено выше. Если вы закомментируете trap DEBUG вы можете использовать ее для отображения кода возврата каждой команды в конвейере.

(Кроме того, поскольку на него ссылается, хук функции command_not_found - это bash-4.0+.)

1

Ниже решение работает для того, что вы хотите:

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

В основном, вышеупомянутая команда печатает stderr красным цветом.

Проверьте ниже снимок экрана:

Я не знаю, как сделать это постоянным. Тем не менее, это, безусловно, должно дать вам несколько советов.

0

Поместите это в файл ~/.bashrc или ~/.bash_profile для постоянного исправления или, если вы хотите, чтобы оно было временным, просто введите это в bash .

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

Это заставит bash выводить команду not found, ошибка выделена жирным шрифтом и красным цветом. Идите вперед и выньте tput bold; чтобы сделать так, чтобы сообщение об ошибке не было выделено жирным шрифтом, или измените tput setaf 1 на другой номер для другого цвета. Надеюсь, поможет!!

РЕДАКТИРОВАТЬ

Вот новая и улучшенная версия выше:

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
}

РЕДАКТИРОВАТЬ 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.

Взято с man-страницы bash

Так что, если это не работает, возможно, ваша оболочка не является верной bash , или это модифицированная версия bash .

0

Может быть, вы можете попробовать hilite - я думаю, что это одно из самых простых решений.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .