bash: друкувати stderr червоним кольором


122

Чи є спосіб зробити башти відображати більш жорсткі повідомлення червоним кольором?


4
Я думаю, що bash ніколи не забарвить свій вихід: якась програма може захотіти щось проаналізувати, і колоризація зіпсує дані з уникнутими послідовностями. Гадаю, додаток GUI повинен обробляти кольори.
колипто

Поєднання відповіді Баласа Позасара і killdash9 дає чіткий результат: function color { "$@" 2> >(sed $'s,.*,\e[31m&\e[m,') } працює на баш і зш. Неможливо додати це як відповідь репутації.
Генріх Хартманн

1
Я чекаю відповіді, яка змінює баш для цього. Рішення нижче всіх насправді модифікують stderr і, можливо, навіть впорядковують wrt stdout, що порушує речі, коли повинна зберігатися точна послідовність байтів stderr, наприклад, при трубопроводі.
masterxilo

Відповіді:


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

6
Чудово! Але мені цікаво, чи є спосіб зробити це постійним :)
kolypto

9
Чудова порада! Пропозиція: Додавши >&2прямо раніше ; done), вихід, призначений для stderr, насправді записується в stderr. Це корисно, якщо ви хочете зафіксувати нормальний вихід програми.
henko

8
Наступне використовує tput, і, на мою думку, трохи читабельніше:command 2> >(while read line; do echo -e "$(tput setaf 1)$line$(tput sgr0)" >&2; done)
Стефан Ласєскі

2
Я думаю, що виконання 2 процесів tput для кожного вихідного рядка зовсім не елегантне. Можливо, якщо ви зберегли б результат команд tput у змінній та використали їх для кожного відлуння. Але знову ж таки, читабельність насправді не краща.
Balázs Pozsár

1
Це рішення не зберігає пробілів, але мені це подобається за його стислість. IFS= read -r lineповинен допомогти, але ні. Не знаю чому.
Макс Мерфі

89

Спосіб 1: Використання процесу заміщення:

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

Спосіб 2: Створіть функцію в скрипті bash:

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

Використовуйте його так:

$ color command

Обидва методи покажуть команду stderrчервоним кольором.

Продовжуйте читати, щоб пояснити, як працює метод 2. Є кілька цікавих особливостей, продемонстрованих цією командою.

  • color()... - Створює функцію bash під назвою color.
  • set -o pipefail- Це варіант оболонки, який зберігає код повернення помилки команди, вихід якої передається в іншу команду. Це робиться в підзаголовку, який створюється в дужках, щоб не змінювати параметр pipefail у зовнішній оболонці.
  • "$@"- Виконує аргументи функції як нова команда. "$@"еквівалентно"$1" "$2" ...
  • 2>&1- Перенаправляє stderrкоманду на stdoutтак, щоб вона стала sed's stdin.
  • >&3- Скорочене зображення для 1>&3цього, перенаправляє stdoutдо нового дескриптора тимчасового файлу 3. 3повертається stdoutпізніше.
  • sed ...- Через перенаправлення вище, sed's stdin- stderrце виконана команда. Його функція полягає в оточенні кожного рядка кольоровими кодами.
  • $'...' Конструктивна графіка, яка змушує його розуміти символи, що вийшли з косої риски
  • .* - Збігає весь рядок.
  • \e[31m - послідовність аварійної передачі ANSI, яка спричиняє червоний колір наступних символів
  • &- Символ sedзаміни, який розширюється на весь відповідний рядок (у цьому випадку весь рядок).
  • \e[m - послідовність аварійної передачі ANSI, яка скидає колір.
  • >&2- стенографія для 1>&2, це перенаправляє sed«s stdoutдо stderr.
  • 3>&1- Перенаправляє дескриптор тимчасового файлу 3назад в stdout.

9
+1 найкраща відповідь! абсолютно занижено!
muhqu

3
Чудова відповідь і ще краще пояснення
Даніель Серодіо

Чому потрібно робити все додаткове перенаправлення? здається, overkill
qodeninja

1
Чи є спосіб змусити його працювати zsh?
Ейал Левін

1
ZSH не розпізнає форми стенографічного перенаправлення. Просто потрібні ще два 1-х, тобто:zsh: color()(set -o pipefail;"$@" 2>&1 1>&3|sed $'s,.*,\e[31m&\e[m,'1>&2)3>&1
Рекін

26

Ви також можете перевірити stderred: https://github.com/sickill/stderred


Нічого собі, ця утиліта чудова, єдине, що їй знадобиться - це мати влучне сховище, яке встановлює її для всіх користувачів, одним рядком, не потрібно робити більше роботи, щоб її ввімкнути.
sorin

Здавалося б, добре працює, коли я тестував його за допомогою сценарію складання в окремому терміналі, але я вагаюся використовувати його глобально (в .bashrc). Дякую, хоча!
Джоел Пурра

2
У OS X El Capitan спосіб роботи (DYLD_INSERT_LIBRARIES) "порушений" у системних бінарних файлах, оскільки вони захищені SIP. Тому може бути краще скористатися варіантами bash, наведеними в інших відповідях.
hmijail

1
@hmijail для MacOS, будь ласка, дотримуйтесь github.com/sickill/stderred/isissue/60, щоб ми могли знайти вирішення, часткове вже існує, але воно є дещо помилковим.
sorin

15

Баш спосіб перетворення stderr в червоний колір використовується "exec" для перенаправлення потоків. Додайте до bashrc:

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

Я писав про це раніше: Як встановити колір шрифту для STDOUT та STDERR



1
Це найкраща відповідь на сьогодні; простий в реалізації без установки / не потребує привілеїв sudo, і може бути узагальнений до всіх команд.
Люк Девіс

1
На жаль, це не добре працює з ланцюжком команд (команда && nextCommand || errorHandlerCommand). Вихід помилки йде після виходу errorHandlerCommand.
carlin.scott

1
Так само, якщо я source ~/.bashrcдвічі з цим, мій термінал в основному блокується.
Дельф

@Dolf: У моєму файні bashrc я легко захищаю це з оточуючим, якщо заява запобігає перезавантаженню цього коду. В іншому випадку проблема полягає у переадресації 'exec 9> & 2' після того, як переадресація вже відбулася. Можливо, змініть його на постійне, якщо ви знаєте, де спочатку вказує> 2.
Євангеліє


7

Я створив обгортковий сценарій, який реалізує відповідь Балаша Позара чистою душею. Збережіть це у ваших $ PATH та префіксальних командах, щоб розфарбувати їх вихід.

    #! / бін / баш

    якщо [$ 1 == "--help"]; тоді
        echo "Виконує команду і розфарбовує всі виниклі помилки"
        echo "Приклад:` basename $ {0} `wget ..."
        echo "(c) o_O Tync, ICQ # 1227-700, насолоджуйтесь!"
        вихід 0
        фі

    # Темп-файл, щоб знайти всі помилки
    TMP_ERRS = $ (mktemp)

    # Виконати команду
    "$ @" 2>> (під час читання рядка; виконайте відлуння -e "\ e [01; 31m $ line \ e [0m" | tee - додайте $ TMP_ERRS; зроблено)
    EXIT_CODE = $?

    # Показувати всі помилки ще раз
    якщо [-s "$ TMP_ERRS"]; тоді
        echo -e "\ n \ n \ n \ e [01; 31m === ПОМИЛКИ === \ e [0м"
        кіт $ ​​TMP_ERRS
        фі
    rm -f $ TMP_ERRS

    # Фініш
    вихід $ EXIT_CODE


2
Це може бути більш ефективним, якби "| tee ..." було поставлено після "done".
Джуліано

3

Ви можете використовувати таку функцію


 #!/bin/sh

color() {
      printf '\033[%sm%s\033[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

Додаю> & 2 для друку на stderr


4
Не вирішення проблеми. Ви не надали спосіб відокремити stderr від stdout, чим це цікавить ОП.
Jeremy Visser

1

У мене є дещо змінена версія сценарію O_o Tync. Мені потрібно було зробити ці моди для OS X Lion, і це не ідеально, оскільки сценарій іноді завершується ще до того, як завершена команда. Я додав сон, але впевнений, що є кращий спосіб.

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

1

Це рішення спрацювало для мене: https://superuser.com/questions/28869/immediate-tell-which-output-was-sent-to-stderr

Я поклав цю функцію на своє .bashrcабо .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\1$(echo -en \\033)[0m/") 3>&1 1>&2 2>&3
}

Тоді наприклад:

$ rse cat non_existing_file.txt

дасть мені червоний вихід.


Ви можете додати set -o pipefail;до (evalкоду виходу для переадресації
kvaps

також додайте в "eval, щоб зберегти пробіли в аргументах
kvaps


0

версія з використанням 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.