Как установить цвет шрифта для STDOUT и STDERR - программирование

Как установить цвет шрифта для STDOUT и STDERR

Я хочу различать сообщения STDOUT и STDERR в моем терминале. Если script или команда печатает сообщение в терминале, я хочу различать цвета; возможно ли это?

(например, цвет шрифта stderr красный, а цвет шрифта stdout - синий.)

Пример (полужирный):

$date
Wed Jul 27 12:36:50 IST 2011

$datee
bash: datee: command not found

$alias ls
alias ls='ls --color=auto -F'

$aliass ls
bash: aliass: command not found

4b9b3361

Ответ 1

Вот хак, о котором я думал, и он работает:

Учитывая следующие псевдонимы для читаемости:

alias blue='echo -en "\033[36m"'
alias red='echo -en "\033[31m"'
alias formatOutput='while read line; do blue; echo $line; red; done'

Теперь вам нужно сначала установить цвет шрифта в вашем терминале на красный (как по умолчанию, который будет использоваться для stderr). Затем запустите свою команду и пропустите stdout через formatOutput, определенный выше (который просто печатает каждую строку как синюю, а затем сбрасывает цвет шрифта до красного):

shell$ red
shell$ ls / somenonexistingfile | formatOutput

Вышеуказанная команда будет печататься как в stderr, так и в stdout, и вы увидите, что линии окрашены по-разному.

Надеюсь, что это поможет


UPDATE:

Чтобы сделать это многоразовым, я поместил все это в маленький script:

$ cat bin/run 
#!/bin/bash
echo -en "\033[31m"  ## red
eval $* | while read line; do
    echo -en "\033[36m"  ## blue
    echo $line
    echo -en "\033[31m"  ## red
done
echo -en "\033[0m"  ## reset color

Теперь вы можете использовать это с любой командой:

$ run yourCommand

Ответ 2

Создайте функцию в оболочке bash или script:

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

Используйте его следующим образом:

$ color command -program -args

Показывает команду stderr красным цветом.

Продолжайте читать для объяснения того, как это работает. Есть некоторые интересные функции, продемонстрированные этой командой.

  • color()... — Создает функцию bash, называемую цветом.
  • set -o pipefail — Это опция оболочки, которая сохраняет код возврата ошибки команды, выход которой передается в другую команду. Это делается в подоболочке, которая создается скобками, чтобы не изменять параметр pipefail во внешней оболочке.
  • "[email protected]" — Выполняет аргументы функции как новую команду. "[email protected]" эквивалентно "$1" "$2" ...
  • 2>&1 — Перенаправляет команду stderr в команду stdout, чтобы она стала sed stdin.
  • >&3 — Сокращение для 1>&3, это перенаправляет stdout в новый временный дескриптор файла 3. 3 позже перенаправляется в stdout.
  • sed ... — Из-за переадресаций выше sed stdin является stderr выполненной команды. Его функция состоит в том, чтобы окружать каждую строку цветовыми кодами.
  • $'...' Конструкция bash, которая заставляет его понимать символы с обратным слэшем.
  • .* — Совпадает со всей строкой.
  • \e[31m — Последовательность escape-кода ANSI, которая вызывает следующие символы:
  • & — Символ замены sed, который расширяется до всей согласованной строки (вся строка в этом случае).
  • \e[m — ANSI escape-последовательность, которая сбрасывает цвет.
  • >&2 — Сокращение для 1>&2, это перенаправляет sed stdout на stderr.
  • 3>&1 — Перенаправляет временный дескриптор файла 3 обратно в stdout.

Ответ 3

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

export COLOR_RED="$(tput setaf 1)"
export COLOR_RESET="$(tput sgr0)"

exec 9>&2
exec 8> >(
    perl -e '$|=1; while(sysread STDIN,$a,9999) {print 
"$ENV{COLOR_RED}$a$ENV{COLOR_RESET}"}'
)
function undirect(){ exec 2>&9; }
function redirect(){ exec 2>&8; } 
trap "redirect;" DEBUG
PROMPT_COMMAND='undirect;'

Так что происходит? Ловушка отладки выполняется непосредственно перед и сразу после выполнения команды. stderr, таким образом, перенаправляется до выполнения команды для включения красного вывода. PROMPT_COMMAND оценивается до отображения приглашения, и при этом я восстанавливаю stderr в нормальное состояние. Это необходимо, потому что PS1 и PS2 (ваше приглашение) печатаются поверх stderr, и я не хочу красную подсказку. volila, красный вывод над stderr!

Ответ 5

Да это не возможно изначально. Вам придется взломать управление tty (в ядре).

Я как-то закончил небольшую обертку C до того, как увидел другие ответы:-) Может быть ошибкой, а значения жестко запрограммированы, не используйте это, кроме как для тестирования.

#include "unistd.h"
#include "stdio.h"
#include <sys/select.h>

int main(int argc, char **argv)
{

char buf[1024];
int pout[2], perr[2];
pipe(pout); pipe(perr);

if (fork()!=0)
{
    close(1); close(2);
    dup2(pout[1],1); dup2(perr[1],2);
    close(pout[1]); close(perr[1]);
    execvp(argv[1], argv+1);
    fprintf(stderr,"exec failed\n");
    return 0;
}

close(pout[1]); close(perr[1]);

while (1)
{
    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(pout[0], &fds);
    FD_SET(perr[0], &fds);
    int max = pout[0] > perr[0] ? pout[0] : perr[0];
    int v = select(max+1, &fds, NULL, NULL, NULL);
    if (FD_ISSET(pout[0], &fds))
    {
        int r;
        r = read(pout[0], buf, 1024);
        if (!r) {close(pout[0]); continue;}
        write(1, "\033[33m", 5);
        write(1, buf, r);
        write(1, "\033[0m", 4);
    }
    if (FD_ISSET(perr[0], &fds))
    {
        int r;
        r = read(perr[0], buf, 1024);
        if (!r) {close(perr[0]); continue;}
        write(2, "\033[31m", 5);
        write(2, buf, r);
        write(2, "\033[0m", 4);
    }

    if (v <= 0) break;
}

return 0;
}

Изменить:. По сравнению с решением оболочки, это будет сохранять порядок строк/символов чаще. (Невозможно быть таким точным, как прямое чтение tty.) Нажатие ^ C не покажет уродливое сообщение об ошибке, и оно корректно ведет себя в этом примере:

./c_color_script sh -c "while true; do (echo -n a; echo -n b 1>&2) done"

Ответ 6

Я удивлен, что никто не понял, как цветные потоки stdio. Это будет красным цветом stderr для всей (суб) оболочки:

exec 3>&2
exec 2> >(sed -u 's/^\(.*\)$/'$'\e''[31m\1'$'\e''[m/' >&3)

В этом случае &3 будет удерживать исходный поток stderr.

Вы не должны передавать какие-либо команды exec, а только перенаправлять. Этот специальный случай заставляет exec заменять потоки stdio текущей (суб) оболочки на те, которые он получает.

Есть несколько предостережений:

  • Так как sed будет постоянно работать в параллельной подоболочке, любой прямой вывод сразу после записи в цветной stdio, вероятно, будет бить sed в tty.
  • Этот метод использует дескриптор файла FIFO; Узлы FIFO работают только в строках. Если вы не будете писать поток строк в поток, ваш вывод будет буферизован до появления новой строки. Это не буферизация на части sed: как работают эти типы файлов.

Самое сложное из предостережений - первое, но состояние гонки можно более или менее избегать, применяя подобную обработку ко всем выходам, даже если вы используете цвет по умолчанию.

Вы можете выполнить аналогичную обработку для одиночных команд по трубопроводу с той же командой sed с обычным оператором трубы (|). Трубопроводные цепи выполняются синхронно, поэтому никаких условий гонки не произойдет, хотя последняя команда в цепочке трубопроводов по умолчанию получает свою собственную подоболочку.