Библиотека сайта rus-linux.net
Оформление вывода в shell-сценариях
Big Shadow
Киев, 2003
В этой заметке будут обсуждаться:
- сюрпризы, которые может нам преподнести команда echo (читается как эхо);
- способы «расцвечивания» результатов работы наших сценариев;
- возможности управления перемещением курсора, очисткой экрана, раздвижкой и сдвижкой строк;
- использование и назначение программы tput и баз данных termcap и terminfo.
Коварное эхо
Как вы знаете, команда echo помещает в стандартный вывод свои аргументы, разделенные пробелами, и завершаемые символом перевода строки.Однако, в 70-е годы прошлого века не все было так одназначно. Существовал один филосовский вопрос. Суть его была такова: что должна делать команда echo, если ей не передали аргументов, в частности, следует ли ей выдавать пустую строку или вообще ничего не предпринимать? По этому поводу велись большие дебаты. Такие, что вдохновили Дуга МакИлроя /Doug McIlroy/ сочинить притчу, которая приведена ниже.
UNIX и эхо.
Жила-была в стране Нью-Джерси, прекрасная девушка UNIX, к которой приезжали издалека, чтобы полюбоваться ею. Ослепленные чистотой UNIX, все искали ее руки и сердца: одни ≈ за изящество, другие ≈ за изысканную вежливость, третьи ≈ за проворность при выполнении самых изнурительных заданий. Была она от рождения столь великодушна и услужлива, что все женихи остались довольны ею, а ее многочисленное потомство распространилось во все концы земли.Сама природа покровительствовала UNIX и вторила ей более охотно, чем кому-либо из смертных. Простые люди поражались ее эхом, таким оно было точным и кристально чистым. Они не могли поверить, что ей отвечают те же леса и скалы, которые так искажают их собственные голоса. Когда один нетерпеливый пастушок попросил UNIX: "Пусть эхо ответит ничего", и она послушно открыла рот, эхо промолчало. "Зачем ты открываешь рот? ≈ спросил пастушок. ≈ Отныне никогда не открывай его, если эхо должно ответить ничего!". ≈ и UNIX подчинилась.
"Но я хочу совершенного исполнения, даже если эхо отвечает ничего, ≈ потребовал другой, обидчивый, юноша, ≈ а никакого совершенного эха не получится при закрытом рте". Не желая обидеть никого из них, UNIX согласилась говорить разные "ничего" для нетерпеливого и обидчивого юношей. Она называла "ничего" для обидчивого как '\n'. Однако теперь, когда она говорила '\n', на самом деле она не произносила ничего, поэтому ей приходилось открывать рот дважды: один раз, чтобы сказать '\n', и второй раз, чтобы не сказать ничего. Это не понравилось обидчивому юноше, который тотчас сказал: "Для меня '\n' звучит, как настоящее "ничего", но когда ты открываешь рот второй раз, то все портишь. Возьми второе "ничего" назад". Услужливая UNIX согласилась отказаться от некоторых эхо и обозначила это как '\с'. С тех пор обидчивый юноша мог услышать совершенное эхо "ничего", если он задавал '\n' и '\с' вместе, но говорят, что он так и не услышал его, поскольку умер от излишеств в обозначениях. [1]
Хотя все настоящие реализации этой команды выдают пустую строку, это еще не значит, что проблемы закончились. Давайте их рассмотрим. Рекомендую все, о чем я буду рассказывать, проверить на практике, сидя за консолью. Так будет легче разобраться.
Уже в 7-ой редакции UNIX echo распознавала флаг -n, который
подавлял вывод завершающего символа перевода строки:
$ echo -n Seven Edition
Seven Edition$
В System V, где команда echo умеет интерпретировать упраляющие последовательности
вида \Х, для подавления вывода завершающего символа перевода строки используют обозначение
\с. Поэтому вызвав echo с аргументом -n вы можете
получить не совсем то, что ожидали:
$ echo -n System V
-n System V
$
В Linux же, echo не желает обрабатывать последовательности вида \Х:
$ echo Linux\\с
Linux \с
$
до тех пор, пока вы не зададите ей флаг -e:
$ echo -e Linux\\с
Linux$
Можно воспользоваться и флагом -n, echo из Linux его понимает.
Добавляет путаницы и то, что почти всегда shell имеет встроенную команду echo, поведение которой может отличаться от внешней /bin/echo. Кроме того, в системе может оказаться не одна echo, а парочка. В таком случае, второе echo обычно находится где-нибудь в районе /usr/ucb/. Из-за таких различий в реализации echo возникают определенные трудности при переносе сценариев из системы в систему. Есть ли способ их избежать? Конечно, но это уже другая история...
Да будет цвет!
Каким образом происходит задание цвета символов и фона, а также переключение различных режимов отображения терминала в UNIX (и во множестве других ОС)? Да также, как и в легендарные времена телетайпных терминалов ≈ посылкой на устройство отображения управляющих команд в виде esc-последовательностей (esc сокр. от англ. escape, произносится как эскейп). Такая последовательность состоит из двух или более символов, первый из которых будет esc (десятичный код равен 27, восьмеричный ≈ 033, шестнадцатеричный ≈ 0x1B; во многих программах и конфигурационных файлах обозначается как \e, \E или ^[).Перед тем как перейти к детальному рассмотрению esc-последовательностей, давайте вначале научимся вводить символ esc с клавиатуры (если вы умеете это делать, то можете переходить к выполению примеров из следующего абзаца). Чтобы ввести с клавиатуры код любой "непечатной", т. е. управляющей клавиши (функциональной, стрелки и т. п.), необходимо нажать Ctrl+V, а затем интересующую вас "кнопку". Этот прием будет работать не только в командной строке, но и в текстовом редакторе vi.
Проверим на практике. Выполним команду echo "Ctrl+V,Esc[30;40m";clear
(на экране символ esc будет показан как ^[):
$ echo "^[[30;40m";clear
Если вы все сделали правильно, то
приобретайте прибор ночного видения :)! Пожалуй я не ошибусь, предположив, что у вас возникли
вопросы:
≈ А что это за числа? К чему они ведут? "А вдруг они не курят, а вдруг они не пьют?"
[2]
≈ Числа 30 и 40 это аргументы команды esc[
n
m.
При необходимости указать несколько аргументов, их перечисляют через точку с запятой:
esc[
n1
;
n2
;...m.
В зависимости от значения n результаты будут следующими:
================================================================== k | n=k - установка | n=k+30 - установка | цвет символов | режима | цвета символов | в режиме | отображения | n=k+40 - установка | повышенной | символов | цвета фона | яркости --|----------------------|-------------------------|-------------- 0 | сброс всех атрибутов | черный | серый 1 | яркий (утолщенный) | красный | розовый 2 | тусклый | зеленый | салатовый 3 | | коричневый | желтый 4 | подчеркнутый | синий | светло-синий 5 | мигающий | фиолетовый | лиловый 6 | | бирюзовый | голубой 7 | реверсный | белый | ярко-белый ==================================================================Теперича, имея в своем распоряжении такую табличку, можете приступать к получению "синих экранов", "красных квадратов" и прочей творческой работе. В которой желаю вам всяческих успехов (тем кто предпочитает другие слова ≈ удачи)!!!
Что еще могут esc-последовательности?
Управлять перемещением курсора по экрану:-
esc[s или
esc7 - запомнить положение курсора
-
esc[u или
esc8 - восстановить запомненное положение курсора
- escc
- очистить экран и установить курсор в левый верхний угол
- esc[ n A
- вверх на n строк
-
esc[
n
B или
esc[ n e - вниз на n строк
-
esc[
n
C или
esc[ n a - вправо на n позиций
- esc[ n D
- влево на n позиций
- esc[ n E
- в начало строки и на n строк вниз
- esc[ n F
- в начало строки и на n строк вверх
-
esc[
n1;n2
H или
esc[ n1;n2 f - переместить в позицию n2 строки n1
- esc[ n Z
- на n табуляций назад (как tab, но в обратную сторону)
- esc[ n `
- в той же строке в позицию n
- esc[ n d
- в той же позиции в строку n
- escM
- сдвинуть курсор на строчку вверх, если он находится в самой верхней строке, то сдвинуть содержимое экрана на строчку вниз
Очищать части экрана:
- esc[0J
- от курсора до конца экрана
- esc[1J
- от начала экрана до курсора
- esc[2J
- весь экран
- esc[0K
- от курсора до конца строки
- esc[1K
- от начала строки до курсора
- esc[2K
- всю строку
- esc[ n X
- очистить n знаков справа от позиции курсора
Раздвигать и сдвигать строки на экране:
- esc[ n L
- вставить n пустых строк ниже текущей строки
- esc[ n M
- удалить n строк ниже текущей строки
- esc[ n P
- удалить n знаков справа от курсора (в пределах строки)
- esc[ n @
- вставить n знаков справа от курсора (в пределах строки)
Проведем испытания. Начнем с подготовки рабочего пространства. Выполните команду clear (или просто нажмите Ctrl+L). Затем ≈ более хитрую (напомню, что символы ^[ появляются в результате нажатия клавиш Ctrl+L,Esc):
$ echo '^[[10;10Habc^[[5dXYZ' HаЁршт aw" && stty size > /dev/null 2>&1 ; then # если наш терминал понимает, что такое ширина и высота, # то назначаем кодам esc-последовательностей понятные названия esc=`echo -en "\033"` extd="${esc}[1m" warn="${esc}[1;31m" done="${esc}[1;32m" attn="${esc}[1;33m" norm=`echo -en "${esc}[m\017"` stat=`echo -en "\015${esc}[${COLUMNS}C${esc}[10D"` # ... неинтересное пропускаем rc_done_up="${esc}[1A${rc_done}" rc_failed_up="${esc}[1A${rc_failed}" rc_reset="${norm}" rc_save="${esc}7" rc_restore="${esc}8" function rc_cuu () { echo -en "\033[${1}A"; } # и даже определяем функцию # для перемещения по экрану вверх на заданное число строк else # ну а если терминал не знает где у него верх, а где низ, # то ведем себя проще и выдаем информацию построчно без выкрутасов, # чтобы люди к нам тянулись :) ... |
И небольшое замечание относительно ДОСа. Помните такую ОС? Так вот, если к ней прикрутить стандартный драйвер ANSI.SYS, то все вышеперечисленные esc-последовательности будут работать и там.
1. Брайан Керниган, Роб Пайк
UNIX ≈ универсальная среда программирования
М.: Финансы и статистика, 1992
2. Слова из песни, которые как известно не выбросишь...