Barvy pro shell

25. 9. 2002
Doba čtení: 6 minut

Sdílet

Tento článek by stejně dobře mohl nést i název "Barvy pro terminál", protože bude řeč o tvz. escape sekvencích, které umožňují v terminálu provádět různé uživatelsky atraktivní akce, jako jsou nastavení barvy textu i pozadí nebo změna pozice kurzoru. Použít je lze ve spojení s prakticky všemi programovacími jazyky, ale největšího využití najdou právě v shellových skriptech.

Co to vlastně ty escape sekvence jsou? Proč něco takového vůbec vzniklo? Odpovědi hledejme v hlubokém dávnověku výpočetní techniky. Zařízení zvané terminál se objevilo v době sálových počítačů, aby sloužilo jako prostředek pro komunikaci mezi člověkem a počítačem. Prvním terminálům se podle jejich výrobce říkalo Teletype (zkráceně tty) a byly tzv. dálnopisného typu. Pokud se někdo z dálnopisem nesetkal, tak je to něco jako elektrický psací stroj a mezi jeho základní vlastnosti patří ohromný rámus, ne nepodobný střelbě z automatické zbraně, který při práci vydává. :-) Spojení s mainframem bylo obvykle zabezpečeno přes telefonní linku. Terminál a počítač si mezi sebou vyměňovaly pouze číslice, písmena a pár řídících kódů (carriage return, line feed, form feed, bell, …). Jak šel pokrok dál, objevily se terminály tvořené dvojicí klávesnice-monitor (plus nějaký ten komunikační HW). Tím se uživatelům otevřely nové možnosti jako např. editace řádky před jejím potvrzením či mazání obsahu obrazovky. Všechny nové vlastnosti bylo nutné při přenosu nějakým způsobem zakódovat. Jelikož ale terminály pracovaly s omezenou znakovou sadou (ASCII, EBCDIC), ve které nebylo pro další rozšíření místo (a ani by to nebylo rozumné), zavedly se tzv. escape sekvence – posloupnosti uvozené speciálním znakem, obvykle nazývaným escape.

Přenesme se však z dob sálových počítačů zpět do současnosti. Co se stalo s terminály ? K běžnému osobnímu počítači lze běžně připojit právě jeden monitor a jednu klávesnici. Přestože se na první pohled může zdát, že se opět jedná o terminál, není to tak úplně pravda. Vnější chování je sice stejné jak u PC, tak u terminálu (po stisknutí klávesy ‚A‘ se na obrazovce nakreslí znak ‚A‘), ale vnitřní mechanismy jsou odlišné. U PC se na celém procesu komunikace, od příjmu znaku z klávesnice až po jeho zobrazení na monitoru, podílí procesor počítače. Naproti tomu terminál zpracovává vstupy z klávesnice, posílá je počítači a přijímá od něj znaky, které zobrazuje na monitoru. Komunikace mezi terminálem a počítačem probíhá přes nějaké vstupně/výstupní zařízení (modem, síťová karta, sériový port). Rozhraní, které poskytuje PC uživateli, se proto obvykle nazývá virtuální terminál. Ten často emuluje chování některého z „pravých“ terminálů.

Jak už to bývá ve světě IT obvyklé, každý výrobce při návrhu svého terminálu použil jiné escape sekvence. S postupujícím vývojem navíc přibývala další rozšíření. Dnešní emulátory terminálů jsou proto zatíženy značnou zpětnou (ne)kompatibilitou (viz. /etc/termcap). Pod Linuxem by měly být všechny emulátory kompatibilní alespoň s terminálem VT100 a případně i s jehoANSI rozšířením. Linux ovšem není jediným OS pro platformu x86, který zná escape sekvence. Mnozí pamětníci si zajisté vzpomenou na ovladač ansi.sys, který emuloval ANSI terminál pod DOSem.

Nechme však DOS odpočívat v pokoji a vraťme se k Linuxu (případně k *BSD). Jak tedy vypadají ty ANSI escape sekvence ? Mohou být umístěny kdekoliv v běžném textovém řetězci (ve smyslu jazyka C). Jak už bylo avizováno dříve, prvním znakem sekvence musí být escape. Podíváme-li se do tabulky ASCII kódů, najdeme tam pro escape hodnotu 27. Pro využití pod shellem se ale více hodí zápis 033 v osmičkovém kódu. Dalším členem posloupnosti je znak ‚[‘. Zbytek sekvence tvoří kód akce, která se má provést. Nejlepší asi bude, předvést zápis na nějakém příkladu.

Zadejte v shellu příkaz

echo -e "\033[1;32mHello World! \033[0m"

a pokud je váš terminál barevný a podporuje escape sekvence :-), vypíše zeleně text

Hello World!

Tutéž sekvenci lze zapsat také jako

echo "^[[1;32mHello World! ^[[0m"

kde dvojice „^[“ tvoří zápis znaku escape získaný pomocí kombinace kláves Ctrl-V Esc. Tento způsob zápisu lze použít také při editaci textového souboru např. pomocí VIMu. Výsledný soubor lze poté vypsat příkazem cat a obsažené escape sekvence budou automaticky interpretovány.

Třetí možná forma zápisu je

echo -e "\e[1;32mHello World! \e[0m"

V tomto textu bude kvůli zachování konzistence a přehlednosti nadále používána pouze varianta zápisu v osmičkovém kódu. Pozornému čtenáři jistě neuniklo, že výše uvedený příklad obsahuje dvě escape sekvence. Řetězec „\033[1;32m“ barvu nastavuje a posloupnost „\033[0m“ obnovuje předchozí barevné nastavení.

Kódy pro nastavení barvy textu mají obecně formát  „\033[<A>;<B>m“ , kde A je atribut a B je číslo barvy. Sekvence měnící barvy vždy končí písmenem ‚m‘.

Tabulka č. 343
černá 0;30 tmavě šedá 1;30
červená 0;31 světle červená 1;31
zelená 0;32 světle zelená 1;32
hnědá 0;33 žlutá 1;33
modrá 0;34 světle modrá 1;34
purpurová 0;35 světle purpurová 1;35
azurová 0;36 světle azurová 1;36
světle šedá 0;37 bílá 1;37

Jak je zřejmé z tabulky, má-li A hodnotu nula, nastavuje se tmavý odstín příslušné barvy. Je-li A roven jedné, bude použita světlá barva. U světlých odstínů se objevuje jedna menší záludnost. Některé emulátory terminálu pro X Window totiž mohou v závislosti na aktuálním nastavení namísto světlé varianty barvy zobrazit daný text tučně. Barevné nastavení pod X-ky lze navíc ovlivnit editací souboru  ~/.Xdefaults  .

Pokud je někdo zvědavý, jaké barvy má na svém terminálu k dispozici, může použít tento jednoduchý skriptík.

#!/bin/bash

for B in `seq 30 37` ; do
    echo -ne " \033[0;${B}mBarvy pro shell\033[0m"
    echo -e " \033[1;${B}mBarvy pro shell\033[0m"
done

Mimo nuly a jedničky jsou pro atribut A platné tyto hodnoty :

  • 4 – pro podtržení textu
  • 5 – blikání (pracuje korektně pouze v textovém režimu)
  • 7 – nastavení inverzní barvy textu a pozadí
  • 8 – „neviditelný“ text použitelný např. pro načítání hesla (v celé řadě emulátorů není implementován)

Společně s barvou textu lze měnit i pozadí. Příslušná sekvence má formát „\033[<C>m“, kde C je některý z osmi kódů uvedených v následující tabulce.

Tabulka č. 344
černá 40
červená 41
zelená 42
hnědá 43
modrá 44
purpurová 45
azurová 46
světle šedá 47

Kromě hraní s barvičkami umožňují escape sekvence také pohyb kurzoru po obrazovce. První terminál umožňující řídit pohyb kurzoru nesl označení VT05b a navrhli jej ve firmě DEC (stejně jako celou úspěšnou řadu VT). Některé užitečné escape sekvence související s kurzorem jsou popsány v následující tabulce.

Tabulka č. 345
nastavení pozice kurzoru na
řádek L a sloupec C
„\033[<L>;<C>H“
„\033[<L>;<C>f“
posun kurzoru o N řádků nahoru „\033[<N>A“
posun kurzoru o N řádků dolů „\033[<N>B“
posun kurzoru o N sloupců vpřed „\033[<N>C“
posun kurzoru o N sloupců vzad „\033[<N>D“
smazání obrazovky „\033[2J“
vymazání textu od kurzoru
do konce řádku
„\033[K“
uložení pozice kurzoru
(někdy není implementována)
„\033[s“
obnoveni pozice kurzoru
(někdy není implementována)
„\033[u“

Odstavec o sekvencích pro manipulaci s kurzorem uzavírá následující malá ukázka…

bitcoin_skoleni

#!/bin/bash

echo -ne "\033[2J\033[0;0H"
echo -n "Probiha vypocet ...  "

for I in `seq 1 5`; do
    for J in `seq 1 8`; do
    case $J in
      1|5) S="|" ;;
      2|6) S="/" ;;
      3|7) S="-" ;;
      4|8) S="\\" ;;
    esac
    echo -ne "\033[1D$S"
    usleep 50000
    done
done
echo -ne "\033[2J\033[0;0H"

Zákuskem v pestrém menu escape sekvencí je posloupnost umožňující nastavení titulku na liště okna emulátoru terminálu pod X Window. Jako titulek lze použít libovolný text uvozený řetězcem „\033]0;“ a ukončený znakem bell, jehož kód lze osmičkově zapsat jako „\007“. Zvláštní pozornost si zasluhuje uvozovací řetězec, jelikož jeho druhým znakem je, narozdíl od všech dříve popisovaných escape sekvencí, uzavírací hranatá závorka ‚]‘. Tato sekvence samozřejmě není platná v textovém režimu. Při jejím použití ve skriptu je proto dobré otestovat typ terminálu. Inspirovat se můžete následujícím příkladem.

#!/bin/bash

case "$TERM" in
    "xterm") echo -ne "\033]0;Barvy pro shell\007"
             exit 0 ;;
    "linux") echo "V textovem modu to asi nepujde !"
             exit 1 ;;
esac

echo "Neznamy terminal, nevim co delat ..."
exit 1

Je zřejmé, že výčet escape sekvencí uvedených v tomto textu zdaleka není úplný. Případní zájemci o podrobnější znalosti mohou bádat v souboru  /etc/termcap  a nebo prostudovat informace na adresách

Autor článku