\Escape: Window Title
Minule sme si ukázali, ako pomocou escape sekvencií ofarbiť terminál. Pre lepšiu navigáciu medzi oknami nám môžu poslúžiť nadpisy (window title). Tie sa vedia zobraziť v titulku grafického okna, ak také máme, prípadne v status riadku screenu. Nadpisy sa, podobne ako farby, tiež dajú nastaviť pomocou escape sekvencií.
Xterm
Titulok xterm-kompatibilného terminálu je možné nastaviť pomocou escape
sekvencie esc]0;text^G
(kde ^G
je znak
BEL, ASCII 7, resp. '\a
'). Konkrétnejšie na mieste nuly môžu
byť:
- 2 – nastaví titulok okna
- 1 – nastaví titulok ikony (napr. Eterm)
- 0 – kombinácia 1+2
V praxi je najjednoduchšie veriť nule. Podporujú ju určite
rxvt
, Konsole
, aj PuTTY
. Či to funguje,
overíme jednoducho:
echo -en "\033]0;test\007"
Screen
Veľa ľudí, ktorí pracujú so vzdialeným textovým terminálom, iste používa
screen
. Umožňuje mať spustených viacero okien, ktoré bežia
na vzdialenom stroji, čím sa vyhneme zaveseniu programov pri strate
spojenia, alebo napríklad aj ušetríme prenosové pásmo počas kompilácie
niečoho (prepnutím sa dočasne do menej "ukecaného" okna). Pre tých, čo sa so
screenom ešte nestretli, jednoduchý začiatok získajú prečítaním si prvých pár
odstavcov z
Gentoo Linux
Wiki (žiaľ v tejto chvíli nefunkčné), alebo
man screen(1).
Titulok terminálu, v ktorom screen beží, je nastavovaný priamo screenom,
ovplyvniť ho vieme pomocou jeho príkazu hardstatus string
. Aby
vedel screen povedať terminálu, že hardstatus má vypísať do titulku okna,
potrebuje na to správne termcapinfo. Dobré sú napríklad takéto riadky v
.screenrc
alebo /etc/screenrc
, pre screen verzie
3.x, resp. 4.x:
# part of .screenrc (screen version 3.x) hardstatus string 'myhost: %n* %t -- %W' hardstatus lastline termcapinfo xterm 'hs:ts=\E]2;:fs=\007:ds=\E]2;screen\007'
# part of .screenrc (screen version 4.x) hardstatus string '%H: %-w%{= BW}%50>%n%f* %t%{-}%+w%<' hardstatus lastline termcapinfo xterm 'hs:ts=\E]2;:fs=\007:ds=\E]2;screen\007'
Samotný nadpis okna vo vnútri screenu môžeme nastaviť niekoľkými spôsobmi:
ctrl-a : title názov
ctrl-a A názov
- spustením programu
screen -t názov číslo_okna príkaz
- automaticky na názov spúšťaného príkazu pomocou
shelltitle '$ |sh'
- vypísaním sekvencie
ESCknázovESC\
(ESC je znak escape, k je obyčajné písmeno)
Posledný spôsob (vypísaním escape sekvencie) nám umožní automatizovať, teda
napríklad nastaviť titulok okna podľa názvu aktuálneho adresára
zakomponovaním do promptu apod.
Automatické nastavenie pomocou príkazu screenu shelltitle
sa
zdá byť na prvý pohľad dobré, avšak má vážny nedostatok: aby fungovalo, musí
byť vypísaná sekvencia ESCkESC\
, a teda nemôžeme naraz vypísať
názov aktuálneho adresára a vzápätí názov spúšťaného programu.
Manuálny title
Predchádzajúce poznatky zhrnieme v malom skripte, ktorý nastaví názov
okna pre xterm
alebo screen
(rozpozná ich podľa
premennej $TERM
). Pracovne je nazvaný my-title
:
#!/usr/bin/env bash #:~/bin/my-title # # set window title (in xterm or screen terminal) if [ "$1" = "" ]; then t="`dirs`" else t="$1" fi case $TERM in xterm*) echo -en "\033];`whoami`@`hostname -s`: $t\007" ;; screen*) echo -en "\033k" # 1=login shell, 2=this script run (not sourced) from it if [ "$SHLVL" -le 2 ]; then # if the shell is a login shell, screen must be # running on a different machine - include hostname: echo -en "`hostname -s`:" fi echo -en "$t\033\134" ;; esac
Ak máme na stroji roota, umiestnime ho napríklad do /usr/local/bin/, inak do ~/bin (ktorý máme, samozrejme, v $PATH). Pri spustení s parametrom nastaví titulok podľa neho, inak použije aktuálny adresár.
Automatický title
Vyššie už bola spomenutá možnosť nastavovať titulok automaticky podľa názvu aktuálneho adresára. Trik spočíva v zakomponovaní escape sekvencie do promptu. Treba však rozlíšiť, či budeme vypisovať sekvenciu pre xterm alebo pre screen, a čo vlastne chceme nastaviť ako titulok.
O niečo zložitejšie je dostať názov aktuálne bežiaceho programu do titulku okna. V zásade je niekoľko prístupov:
- alias – vytvoriť si alias pre najčastejšie spúšťané programy,
napríklad:
alias p 'my-title PINE; pine -d 0 -p ~/mail/.pinerc'
- v screene pomocou shelltitle – potom však nie je vidno názov aktuálneho adresára (ako už bolo spomenuté hore)
- mágiou v shelli – vypísaním escape sekvencie s názvom spúšťaného programu tesne pred jeho spustením.
Pri poslednom spôsobe nemôžeme sekvenciu vypísať len tak priamo, pretože
by pri presmerovaných výstupoch (napríklad aj cat | grep | less
)
došlo k výpisu sekvencie do vnútra rúry, čím by sme mohli v horšom prípade
aj niečo pokaziť. Preto treba sekvenciu doručiť nie na stdout, ale na
zariadenie používateľovho terminálu. V rôznych shelloch sa to robí
všelijako.
tcsh
Pre výpis aktuálneho adresára do titulku xtermu stačí zakomponovať do
set prompt=
napríklad reťazec "%{\033]0;%n@%m: %~\007%}
".
Je medzi znakmi %{
a %}
, aby shell vedel,
že ich výpis neovplyvní dĺžku príkazového riadku. V titulku potom budeme mať
zobrazený username@hostname:currentpath.
Vypísanie spúšťaného programu do titulku môžeme dosiahnuť pomocou aliasu
postcmd, ktorý sa vykonáva vždy tesne pred spustením zadaného príkazu. Názov
programu získame z histórie pomocou '!
'. Vypisovať nesmieme na
stdout
, ale do /dev/$tty
. Celý alias môže potom
vyzerať približne takto:
alias postcmd "echo -n "'"'"`cat ~/bin/esc`]0;`whoami`@`hostname -s`: \!#`cat ~/bin/beep`"'"'" > /dev/$tty"
Interný príkaz echo
v tcsh
nepozná parameter
-e
, teda nevieme ním vypisovať špeciálne znaky. Preto si ich
vyrobíme inak – buď použijeme /bin/echo
, ak to podporuje,
alebo bash
. Keďže quotovanie v tcsh
je hrôza,
môžeme mať špeciálne znaky dopredu vyrobené a uložené v súboroch
esc
a beep
:
# making special chars in tcsh: bash -c 'echo -en "\033"' > ~/bin/esc bash -c 'echo -en "\007"' > ~/bin/beep
bash
Aktuálny adresár dostaneme do titulku v bashi veľmi podobne, escape
sekvenciou vo vnútri premennej $PS1
, napríklad reťazcom
"\[\033]0;\u@\h: \w\007\]
". Hranaté zátvorky slúžia na rovnaký
účel, ako zložené pre tcsh.
S výpisom spusteného programu do titulku je to v Bashi horšie. Nemá
ekvivalent 'postcmd' v tcsh
, ani 'preexec' v zsh
.
David
Pashley však vykutral, že by sa na tento účel dal použiť DEBUG trap. Ten
sa vykoná pre každý jednoduchý príkaz. Názov toho príkazu vidno v premennej
$BASH_COMMAND
. Čo je však naozaj problém, je zistiť
názov aktuálneho terminálového zariadenia. (Priamo to ide len cez prompt s
'\l
', cez ktorý sa však trap nastaviť nedá – DEBUG trapy sa
smerom nahor nededia [smerom k deťom len pri zapnutom
set -o functrace
].) Preto na zistenie názvu tty zneužijeme
tcsh -c '$tty'
, alebo program tty
z GNU coreutils,
ak je nainštalovaný. Skrátene:
trap "echo -en '\e]0;`whoami`@`hostname -s`: \$BASH_COMMAND\007' > `tty`" DEBUG
Nevýhodou je, že to bude fungovať len v bash verzii >=3.1, v nižších sa
premenná $BASH_COMMAND
totiž mení aj vo vnútri trapu, resp. je
prázdna. Oproti tcsh
vieme zobraziť len jednotlivé príkazy, a
nie celý zadaný riadok, s tým sa však dá žiť, dokonca niekedy je to tak
prehľadnejšie.
Ďalším nedostatkom je skomolenie názvu jobu kvôli trapu. Nedá sa potom ľahko orientovať medzi zastavenými jobmi, pretože sa všetky volajú rovnako:
^ZYou have suspended the program. Type 'fg' to return [2]+ Stopped echo -en "\ek$BASH_COMMAND\e\134" >/dev/pts/6 matej@aelia:~$ jobs [1]- Stopped echo -en "\ek$BASH_COMMAND\e\134" >/dev/pts/6 [2]+ Stopped echo -en "\ek$BASH_COMMAND\e\134" >/dev/pts/6
S týmto sa dá žiť, najmä ak človek používa viac programy na popredí v
screen
e ako správu jobov na pozadí.
Ultimátna kombinácia
Skombinovaním farieb a titulkov (pre prípady xtermu, screenu lokálne, vzdialeného stroja v screene) v univerzálne použiteľnom bash/C-shell skripte získame celkom pekný shell. Skripty sú trochu dlhšie, na stiahnutie:
- bash farby + titulky
– umiestnime napr. do
/etc/profile.d/
, alebo niekam do homediru (~/bin
).
Pozor, keďžebash
nemá jeden konzistentný rc súbor, ktorý by púšťal zakaždým pre login aj non-login shelly, potrebujeme to spúšťať z.bashrc
:# part of .bashrc . ~/bin/prompt-colors+title.bash
a tiež z
.bash_profile
– ja v ňom štandardne používam:# part of .bash_profile . ~/.bashrc
- tcsh farby + titulky
– umiestnime napr. do
~/bin
a voláme z.cshrc
:# part of .cshrc source ~/bin/prompt-colors+title.csh
Keď skript dáme aj na ostatné stroje, kam sa prihlasujeme, výsledok môže vyzerať takto nejako pre screen: a pre xterm:
Záver
Zobrazenie cesty aktuálneho adresára v titulku xterm
u a
screen
u používam už niekoľko rokov bez žiadnych problémov.
Nedokázal som vtedy vyriešiť vypisovanie bežiaceho programu, zrejme preto,
že screen
to nevedel poriadne, a bash
vôbec :)
– túto vymoženosť som začal používať až pred pár dňami. Zatiaľ som
nenarazil na nejaké veľké neželané vedľajšie efekty, okrem vyššiespomenutého
skomolenia názvu jobu (iba bash
) je to ešte prebliknutie
titulku keď sa vykonávajú krátke príkazy. Zrejme tých pár znakov navyše
zhorší zahltenie linky, ale nie badateľne, a nastavený DEBUG trap možno
trochu znižuje performance – nemám ho však s
-o functrace
, platí teda len pre aktuálny shell a nie pre
skripty.
Zdroje:
Pôvodne uverejnené na portáli blackhole.sk, kde si môžete pozrieť aj diskusiu.