воскресенье, 17 февраля 2008 г.

Подсветка текста в терминале

В этой статье я дам два небольших совета, которые, на мой взгляд, могут сделать работу с консолью слегка комфортнее. Повышать комфорт будем путем подсветки информации, выводимой на терминал.


1. Подсвечиваем приглашение командной строки

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

В ~/.bashrc у меня прописана следующая строка:
PS1='\[\033[01m\]\w\$\[\033[00m\] '
которая заставляет bash выводить приглашение командной строки жирным шрифтом.

На данном скриншоте приведен пример того, как выглядит консоль без подсветки приглашения командной строки (слева) и с подсветкой (справа):

Текст можно делать жирным, подчеркнутым, курсивом, менять его цвет и цвет фона. Приводить примеры того, как это сделать, я не буду, т. к. вам не составит труда найти всю необходимую информацию в интернете (ключевые слова: xterm escape sequences).


2. Подсвечиваем вывод программ

Если вы, например, компилируете какое-либо приложение, то предупреждения, выдаваемые компилятором "тонут" в общем потоке выводимой информации. И хотя эту проблему можно решить при помощи colorgcc (Несколько небольших советов), то с выводом других программ мы ничего сделать не сможем, разве что перенаправить stdin и stdout в разные файлы, что довольно неудобно.

Для решения этой задачи я написал небольшой скрипт. Работает он следующим образом:

Если имя скрипта имеет вид *colorize_errors.sh, то вызов
colorize_errors.sh mplayer video_file.avi
запустит 'mplayer video_file.avi' и подсветит все, что выведет mplayer в стандартный поток ошибок.

Если имя скрипта имеет вид *colorize_output.sh, то вызов
colorize_output.sh mplayer video_file.avi
запустит 'mplayer video_file.avi' и подсветит весь его вывод (может пригодиться при написании скриптов).

Сразу хочу предупредить, что скрипт не лишен недостатков: при подсветке может появиться рассинхронизация потоков вывода, если программа выводит данные довольно часто. Происходит это потому, что подсвеченный текст выводится с небольшим запозданием. Но для большинства задач данный недостаток не очень существенен (по крайней мере мне он не сильно мешает :) ).

Ниже приведен пример работы этого скрипта:

Вообщем, как всегда буду рад, если кому-нибудь пригодится. :)

colorize_errors.sh:
#!/bin/bash
#***************************************************************************
#*   Copyright (C) 2008, Konishchev Dmitry                                 *
#*   http://konishchevdmitry.blogspot.com/                                 *
#*                                                                         *
#*   This program is free software; you can redistribute it and/or modify  *
#*   it under the terms of the GNU General Public License as published by  *
#*   the Free Software Foundation; either version 3 of the License, or     *
#*   (at your option) any later version.                                   *
#*                                                                         *
#*   This program is distributed in the hope that it will be useful,       *
#*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
#*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
#*   GNU General Public License for more details.                          *
#**************************************************************************/

# Скрипт подсвечивает вывод программы, переданной ему в качестве аргумента.
# Если запущен как colorize_errors.sh, то подсвечивает только stderr.
# Если запущен как colorize_output.sh, то подсвечивает stdout и stderr.
#
# Пример вызова:
# colorize_errors.sh mplayer video.avi


# "Теги" окрашивания текста -->
color_start=`echo -e "\033[1;31m"`
color_end=`echo -e "\033[00m"`
# "Теги" окрашивания текста <--

die()
{
echo "${color_start}Error! $@$color_end" >&2
exit 1
}

script_command="$0"

# Определяем по имени скрипта, что именно надо подсвечивать -->
if echo "$script_command" | grep "colorize_output.sh$" > /dev/null
then
colorize_mode="output"
elif echo "$script_command" | grep "colorize_errors.sh$" > /dev/null
then
colorize_mode="errors"
else
die "Colorize output: bad colorize output script name."
fi
# Определяем по имени скрипта, что именно надо подсвечивать <--

# Определяем режим, в котором будет работать скрипт -->
if [ "$1" == '--invert' ]
then
mode='invert'
shift
elif [ "$1" == '--colorize' ]
then
mode='colorize'
shift
else
mode='normal'
fi
# Определяем режим, в котором будет работать скрипт <--

# Проверяем, передал ли пользователь команду -->
if [ "$mode" == 'normal' -o "$mode" == 'invert' ]
then
if [ "$1" == "" ]
then
die "Colorize $colorize_mode: command not setted."
fi
fi
# Проверяем, передал ли пользователь команду <--

# Обычный режим, когда пользователь запускает скрипт
if [ "$mode" == 'normal' ]
then
# Запускаем этот же скрипт и меняем местами потоки вывода,
# т. к. при окрашивании stdout становится stderr и наоборот
if [ "$colorize_mode" == 'output' ]
then
$script_command --invert "$@" 3<&1 1<&2 2<&3 | $script_command --colorize
else
$script_command --invert "$@" 3<&1 1<&2 2<&3
fi
# Режим, в задачу которого входит запуск команды с перенаправлением
# ее выводов в скрипт окрашивания
elif [ "$mode" == 'invert' ]
then
"$@" 3<&1 1<&2 2<&3 | $script_command --colorize
# Режим подсветки данных, поступающих в stdin
elif [ "$mode" == 'colorize' ]
then
while read line
do
echo "$color_start$line$color_end"
done
# Ошибка
else
die 'Logical error!'
fi

5 комментариев:

Pretorean комментирует...

а можно както сделать чтобы увсех программ stderr подсвечивался?
так чтобы не вызывать каждую прогу со скриптом

Конищев Дмитрий комментирует...

Честно говоря, не знаю. И мне кажется, что без правки исходных кодов bash такое вряд ли удастся сделать.

ramok@jabber.org комментирует...

можно.. все можно Ж:-)
вот тут http://rusmafia.org/linux/taxonomy/term/92
целый набор советов по подстведке текста в консоли

ramok@jabber.org комментирует...

каюсь невнемательно прочитал вопрос.
такое сделать поидее можно. так на вскидку
1. делаем mkfifo пайп для ошибок текущего шела
mkfifo /tmp/stderr-$$
2. перенаправляем поток ошибок текущего шела в этот пайп
exec 2>tmp/stderr-$$
3. запускаем в фоне процесс который читает из пайпа, подсвечивает строчки и выводит обратно на терминал
sed -ue 's/.*/ESC-цевета & ESC-отмены-цвета /' /tmp/stderr-$$ &

все..
писано на коленке только что, надо проверить Ж:-)
из недостатков - будет асинхронный вывод ошибок и стандартного вывода

Конищев Дмитрий комментирует...

Да, про exec я как-то и забыл... Спасибо, оставлю себе на заметку. Вполне можно вставить эти строчки в ~/.bashrc. Хотя по мне все-таки лучше уж вручную запускать для каждой команды, если для нее рассинхронизация не влияет роли.