Linux: Kniha kouzel, vanilková příchuť 1.17 (27. února 2022)
Veškerá moc příkazové řádky/příkazového řádku přehledně, pro začátečníky i pokročilé

3. Barvy, titulek a výzva terminálu

Řada 1.x vanilkové příchuti Linuxu: Knihy kouzel je od 1. října 2020 do 1. března 2023 ve stavu dlouhodobé pasivní údržby; nahlášené chyby budou opravovány, ale aktivní vývoj se již věnuje novější vývojové řadě určené pro novější verze operačního systému a programů. Pokud nejste vázáni na starší verze programů, doporučuji vyhledat novou verzi z aktivně vyvíjené vývojové řady.
barvy bash tematický okruh

1. Úvod

Tato kapitola pokrývá ovládání barvy písma, barvy pozadí, použitého fontu, titulku terminálového okna a pozice a vlastností kurzoru. Rovněž pokrývá nastavování výzev interpretu bash (PS1 a dalších). Logicky by patřila do kapitoly o příkazovém interpretu bash, ale ta bude velmi rozsáhlá a náročná na zpracování, proto jsem toto téma vydělil/a do samostatné kapitoly.

Barvy a font se v příkazové řádce Linuxu nastavují pomocí takzvaných escape sekvencí, což jsou zvláštní řídicí sekvence bajtů, kterým daný terminál rozumí a místo jejich vypsání na obrazovku změní písmo, přesune kurzor nebo udělá jinou akci, která je v dané sekvenci zakódována. Abychom se tyto sekvence nemuseli učit, používáme místo nich moderní příkaz „tput“, který načte příslušnou sekvenci ze své databáze a vypíše ji na svůj standardní výstup. Pokud tento výstup směřuje přímo na terminál, požadovaná akce se ihned provede; častěji se ale sekvence ukládá do proměnné k pozdějšímu použití; k její aktivaci pak stačí danou proměnnou vypsat na terminál příkazem jako „printf“ či „echo“.

Tato verze kapitoly nepokrývá zvláštní schopnosti konkrétních terminálových programů (např. rozdíly mezi Terminatorem a Konsolí) a podporu šestnácti milionů barev, která zatím v terminálových programech není dostatečně rozšířena (ačkoliv některé už příslušné escape sekvence podporují).

Jedna z prvních věcí, která mě po otevření linuxového terminálu naštvala, bylo to, že neustále barevně zdůrazňoval moje uživatelské jméno a uváděl ho do titulku snad každého terminálového okna. Když si v Xubuntu ve výchozím nastavení poprvé otevřete Terminator a rozdělíte ho na čtyři podokna, svoje uživatelské jméno uvidíte na deseti místech a zopakuje se pokaždé, když máte zadat další příkaz. Mám z toho pocit, že toto nastavení musel navrhovat někdo s narcistickou poruchou osobnosti... Pokud si to chcete předělat, tato kapitola vám poradí jak.

2. Definice

3. Zaklínadla

3/1 Titulek

nastavit titulek okna terminálu#1 (1)
printf %s\\n "$TERM" | egrep -isq "^(xterm|rxvt)" && printf "\\e]2;%s\\a" "nový titulek"

3/2 Barvy

vypsat vzorník palety (barvy na pozadí)#1
for I in $(seq 0 $(($(tput colors) - 1)))
do
printf "%s %3d %s" "$(tput bold;tput setab $I)" $I "$(tput sgr0)"
test $(($I % 16)) -eq 15 && printf \\n
done
⨿vypsat vzorník palety (barvy textu)#2
for I in $(seq 0 $(($(tput colors) - 1)))
do
printf "%s %3d %s" "$(tput bold;tput setaf $I)" $I "$(tput sgr0)"
test $(($I % 16)) -eq 15 && printf \\n
done
resetovat všechny atributy písma a barev#3
tput sgr0
nastavit barvu popředí/pozadí#4 (2)
^source <(lkk --funkce)
lkk_bezp_set setaf číslo-barvy
lkk_bezp_set setab číslo-barvy
ztmavit text (jen zapnout)#5
tput dim
inverzní režim (dočasně prohodí barvy popředí a pozadí; jen zapnout)#6
tput rev
neviditelný text (text barvou pozadí; jen zapnout)#7
tput invis
zvýrazněný mód (zapnout/vypnout)#8 (3)
tput smso
tput rmso
blikající text (jen zapnout; málo podporovaný)#9 (4)
tput blink
vyplnit celý terminál barvou#10
^source <(lkk --funkce)
lkk_bezp_set setab číslo-barvy [náhradní-číslo-barvy]; tput clear; tput sgr0

3/3 Nastavení písma

vypnout všechny atributy písma a barev#1
tput sgr0
tučné písmo (jen zapnout)#2
tput bold
kurzíva (zapnout/vypnout)#3
tput sitm
tput ritm
podtržení (zapnout/vypnout)#4
tput smul
tput rmul

3/4 Zjistit údaje o terminálu

Zde uvedené příkazy nevypisují escape sekvence, ale konkrétní hodnoty.

počet sloupců/řádků terminálu#1
tput cols⊨ 98
tput lines⊨ 30
počet podporovaných barev (velikost palety)#2
tput colors⊨ 256
aktuální sloupec/řádka kurzoru/obojí do proměnných $Y (řádek) a $X (sloupec)#3
read -rsd R -p $'\e[6n' </dev/tty && printf %s\\n $(($(printf %s\\n "$REPLY" | sed -E 's/.*\[([0-9]+);([0-9]+)/\1/') - 1))
read -rsd R -p $'\e[6n' </dev/tty && printf %s\\n $(($(printf %s\\n "$REPLY" | sed -E 's/.*\[([0-9]+);([0-9]+)/\2/') - 1))
read -rsd R -p $'\e[6n' </dev/tty && eval "$(printf %s\\n "$REPLY" | sed -E 's/.*\[([0-9]+);([0-9]+)/Y=$((\1-1));X=$((\2-1));/')"

3/5 Ovládání kurzoru

uložit/obnovit pozici kurzoru#1
tput sc
tput rc
posun kurzoru na pozici#2 (5)
tput cup číslo-řádku číslo-sloupce
posun kurzoru nahoru/dolů/vlevo/vpravo#3
tput cuu posun
tput cud posun
tput cub posun
tput cuf posun
posun kurzoru do určitého sloupce na aktuální řádce/na začátek řádku#4
tput hpa index-sloupce
tput hpa 0
posun kurzoru do levého horního rohu/levého dolního rohu#5
tput home
tput cup $(tput lines) 0
skrytí kurzoru/zrušení skrytí#6
tput civis
tput cnorm

3/6 Mazání obrazovky

smazat část řádky od kurzoru vlevo/vpravo#1
tput el1
tput el
smazat celou obrazovku a kurzor přesunout na pozici 0 0 (levý horní roh)#2
tput clear
odstranit N řádků od aktuální řádky (včetně) dolů#3

4. Zaklínadla (PS0, PS1 a PS2)

Poznámka: z hlediska odzvláštnění jsou zaklínadla v této sekci upravena pro uvedení uvnitř dvojitých uvozovek v bashi. Při uvedení jiným způsobem (např. v jednoduchých uvozovkách nebo při načítání ze souboru) je tomu nutno zpětná lomítka přizpůsobit.

4/1 Častá

znak $ pro normálního uživatele a # pro uživatele „root“#1
\\\$⊨ $
provedení příkazu a vypsání jeho výstupu (vyhodnotit hned/vyhodnotit při každém vypsání dané výzvy)#2 (6)
$(příkaz)
\$(příkaz)
návratový kód posledního příkazu (viz poznámka!)#3 (7)
\${navr_hodn}⊨ 0
cesta/název aktuálního adresáře (v obou případech se domovský adresář nahrazuje znakem „~“)#4
\\w⊨ ~/Dokumenty
\\W⊨ Dokumenty
aktuální čas ve formátu HH:MM/HH:MM:SS#5
\\A⊨ 15:35
\\t⊨ 15:35:38
aktuální datum ve formátu YYYY-MM-DD/ve vlastním formátu#6 (8)
\\D{%F}⊨ 2020-01-29
\\D{formát}
název počítače (úplný/jen před první „.“)#7
\\H⊨ mars.podnik
\\h⊨ mars
konec řádku/tabulátor#8
\\n
$(printf \\t)
hodnota proměnné při každém vypsání výzvy#9
\\\${název proměnné}
uživatelské jméno přihlášeného uživatele/jeho celé jméno#10
\\u⊨ novakova
$(getent passwd $UID | cut -d : -f 5 | cut -d , -f 1)⊨ Jarmila Nováková

4/2 Méně častá

číslo příkazu (podle historie/pořadové)#1
\\!""⊨ 1984
\\#⊨ 9
označení terminálu (alternativy)#2
\\l⊨ 3 (pro textovou konzoli např. „tty3“)
$(ps h -o tty:1 -p $$)⊨ pts/3 (pro textovou konzoli např. „tty3“)
PID příkazového interpretu#3
\${\$}⊨ 3338
počet úloh běžících na pozadí (těch, které lze vypsat příkazem „jobs“)#4
\\j⊨ 0
počet řádek/sloupců terminálu#5
\${LINES}
\${COLUMNS}
cesta/název aktuálního adresáře (bez zkracování znakem „~“)#6
\$(pwd)⊨ /home/novakova/Dokumenty
\$(basename \$(pwd))⊨ Dokumenty
znak „$“ pro všechny (i pro uživatele root)#7
\$(printf \$)⊨ $

5. Zaklínadla (příklady)

návratová hodnota, čas, aktuální adresář a dolar#1
^source <(lkk --funkce)
PROMPT_COMMAND="navr_hodn=\$?"
PS1="$(lkk_pstput sgr0)\$navr_hodn $(lkk_pstput setaf 6)\A "
PS1+="$(lkk_pstput sgr0; lkk_pstput bold; lkk_pstput setaf 2)\w$(lkk_pstput sgr0)\\\$ "
vedlejší výzva: zelené svislítko#2
^source <(lkk --funkce)
PS2="\\[$(lkk_bezp_set setaf 2)\\]|$(lkk_pstput sgr0) "
příkazy psát červeně na zeleném pozadí, výpisy příkazů tyrkysově na fialové pozadí#3
^source <(lkk --funkce)
PS1="\\[$(lkk_bezp_set setaf 1; lkk_bezp_set setab 2; tput el)\\]\$ "
PS0="$(lkk_bezp_set setaf 6; lkk_bezp_set setab 5; tput el)"

6. Parametry příkazů

nastavit šablonu hlavní výzvy/připojit k ní další text (analogicky platí i pro ostatní výzvy)#1
PS1="text"
PS1+="další text"

Důležitá poznámka: Aby mohl bash správně zformátovat hlavní a vedlejší výzvu (PS1 a PS2), potřebuje předem znát počet tisknutých znaků na každém řádku. Bohužel bash nerozumí escape sekvencím, proto mu musíte napovědět a tyto sekvence uzavřít do zvláštních závorek „\[“ a „\]“ (ve dvojitých uvozovkách se zadávají „\\[“ a „\\]“), které znamenají, že jejich obsah bash nemá při výpočtu šířky řádků vůbec zohledňovat. Tyto závorky se bohužel naopak nesmějí používat v proměnné PS0, tam by vypsaly škaredé paznaky na terminál. V ukázce a v některých zaklínadlech lze tento problém vyřešit tak, že místo přímého zadání příkazu tput použijete pomocnou funkci lkk_pstput.

7. Instalace na Ubuntu

Všechny použité součásti jsou základními nástroji přítomnými v každé instalaci Ubuntu.

8. Ukázka

source <(lkk --funkce)
PROMPT_COMMAND="navr_hodn=\$?;$PROMPT_COMMAND"
PS1="\\[$(printf %s\\n "$TERM" | egrep -isq "^(xterm|rxvt)" && printf "\\e]2;%s\\a" "Bude příkaz č. \\#")\\]"
PS1+="Tato $(lkk_pstput smul)výzva je $(lkk_pstput sitm)zbytečně$(lkk_pstput rmul) rozsáhlá, aby ukázala $(lkk_pstput bold)spoustu$(lkk_pstput sgr0) možností.\\n"
PS1+="$(lkk_pstput dim)Velikost terminálu: \$(tput cols)x\$(tput lines) Volné místo: $(lkk_pstput smul)\$(df -h --output=avail . | tail -n 1 | tr -d \" \")$(lkk_pstput sgr0)\\n"
PS1+="Návr.kód:\\[\$(lkk_barvapronh \${navr_hodn})\\]\${navr_hodn}$(lkk_pstput sgr0) (\\[$(lkk_bezp_set setaf 87 6)\\]\\t$(lkk_pstput sgr0)) !""\\! "
PS1+="\\[$(lkk_bezp_set setaf 220 3; tput bold)\\]\\w$(lkk_pstput sgr0) \\$ "
PS2="\\[$(lkk_bezp_set setaf 10 2; tput bold)\\]| $(lkk_pstput sgr0)"

9. Tipy a zkušenosti

10. Další zdroje informací

Přehled syntaxe pro proměnné PS0, PS1 a PS2 najdete v sekci „PROMPTING“ v manuálové stránce „bash“ (anglicky).

Různé další tipy se dají najít v článku Bash/Prompt customization (anglicky).

11. Pomocné funkce

lkk_bezp_set() – nastaví písmo či pozadí na první podporovanou barvu#1
function lkk_bezp_set () {
local f="$1" c="$(tput colors 2>/dev/null || printf 0)" x=""
shift
for x in $@; do if test $x -lt $c; then tput $f $x; break; fi; done
return 0
}
lkk_barvapronh() – nastaví barvu písma podle hodnoty parametru#2
function lkk_barvapronh () {
test $1 -gt 0 && tput bold
test $1 -eq 1 && lkk_bezp_set setaf 1
test $1 -gt 1 && lkk_bezp_set setaf 2
}
lkk_pstput() – vypíše escape sekvenci uzavřenou pro použití v proměnných PS1 a PS2#3
function lkk_pstput () {
printf \\[; tput "$@" && printf \\]
}

12. Snímek obrazovky

snímek obrazovky
1 Ve výchozím nastavení nastavuje titulek terminálu jeho hlavní výzva PS1. Proto ji musíte před experimentováním vypnout, např. příkazem „PS=""“, jinak vám vaše nové nastavení hned přepíše a ani si toho nevšimnete.
2 Funkce „lkk_bezp_set“ použije ze svých argumentů první podporované číslo barvy. Není-li žádné z uvedených čísel podporováno, žádná barva se nanastaví. Při volání doporučuji jako první uvést číslo pro paletu s 256 barvami a jako druhé číslo náhradní barvy z osmibarevné palety.
3 Na některých terminálech je realizován jako inverzní text, na jiných jako tučné písmo.
4 Používání blikajícího textu se výrazně nedoporučuje, protože je v různých terminálech málo a nejednotně podporován, má mnoho odpůrců a může uživateli způsobovat zdravotní potíže.
5 Řádky a sloupce jsou číslovány od nuly od levého horního rohu terminálu.
6 U druhé varianty (vyhodnotit při každém vypsání výzvy) musíte v příkazu odzvláštnit znaky ", \, $ a !, aby se do příslušné proměnné uložil přesně tak, jak má být vykonán.
7 Poznámka: Aby tento výraz fungoval, musíte do proměnné PROMPT_COMMAND (ideálně na začátek) přidat příkaz „navr_hodn=$?“, např. příkazem „PROMPT_COMMAND="navr_hodn=\$?;$PROMPT_COMMAND"“.
8 Pro popis vlastního formátu viz „man strftime“ nebo kapitolu „Datum, čas a kalendář“.
VimGitDiskové oddíly