Hlavní navigace

Bash-completion: inteligentní doplňování příkazů

20. 8. 2009
Doba čtení: 4 minuty

Sdílet

Velmi příjemnou vlastností moderních příkazových řádek je automatické doplňování. Za normálních okolností Bash doplňuje pouze příkazy, adresáře a proměnné, což je samo o sobě velmi užitečné. Můžeme jej ale naučit doplňovat podstatně více než jen to. Jeho rozšíření bash-completion umí doplnit cokoliv.

Programovatelné doplňování je součástí Bash shellu už poměrně dlouhou dobu. Přinesla jej verze 2.04, která vyšla na začátku roku 2000. Přesto ale nejsou informace o této extrémně užitečné funkci obecně příliš známé. Abychom to změnili, rozhodli jsme se ukázat vám možnosti funkce nazvané bash-completion.

Co to je?

Běžný shell umí doplnit jen věci, které dokáže přímo rychle zjistit. Obvykle to bývají názvy souborů, názvy adresářů (tedy cesty), systémové proměnné a několik dalších podobných údajů. Existuje ale řada dalších informací, které bychom chtěli doplnit, namátkou třeba:

  • parametry příkazů
  • názvy počítačů (třeba za SSH)
  • názvy balíků za balíčkovacím systémem
  • ovládací příkazy CVS
  • mailové adresy
  • cokoliv dalšího…

Tyto informace ale shell nedokáže nijak rychle vyhledat na disku, a proto je nedokáže také sám od sebe použít. Navíc nám do hry vstupuje kontext, kdy je třeba doplnit to správné na tom správném místě. Do doplňující polévky je tedy třeba zamíchat také kus inteligence.

Tuto funkci právě zajišťuje bash-completion. Ten neobsahuje rozšířené doplňování jako jediný, ale můžete jej najít také v zsh nebo v tcsh (a určitě dalších). My se ovšem budeme zabývat tím, jak to chodí v Bashi.

Chci to nainstalovat!

Instalace je poměrně snadná, stačí nainstalovat balíček bash-completion. Je možné, že ve vašem systému už bude nainstalovaný. Tento balíček není platformně závislý a obsahuje definice doplňování pro ohromné množství běžně používaných příkazů. Jeho velikost po rozbalení je asi 500 KB.

Programovatelné doplňování funguje v principu tak, že shell má k dispozici sadu skriptů, ve kterých je definováno co je třeba hlídat a co je možno na kterou pozici za příkazem doplňovat. Tyto skripty jsou uloženy v adresáři /etc/bash_completion.d/ a běžně dodávaný balík vám jich dodá asi čtyřicet (záleží ale na distribuci).

Pro spuštění pak stačí na řádku napsat

$ . /etc/bash_completion

Pokud chcete mít funkci zapnutou trvale, uložte tento řádek na konec souboru ~/.bashrc svého uživatele nebo do /etc/bashrc pro všechny uživatele. Pak je třeba se přihlásit a odhlásit.

Co to umí?

Můžete si vyzkoušet namátkou některé doplňovací funkce. Například na

$ aptitude in[tab]

vám automaticky Bash doplní install. Můžeme ale pokračovat a zapsat

$ aptitude install seam[tab]

a Bash nabídne k instalaci balíčky seamonkey-browser a seamonkey-mailnews. Vidíte, že funguje i kontextové doplňování. Bash vidí, že chceme instalovat (podle předchozího příkazu) a hledá v databázi dostupných balíčků.

Stejně tak můžeme vyzkoušet doplňování klasických parametrů:

$ mplayer * -shu[tab]

automaticky doplní -shuffle. Možností je samozřejmě daleko více, předpřipravené skriptíky toho umí opravdu hodně.

A co když tohle právě neumí?

Tady bychom mohli pro mnoho čtenářů skončit. Funkční to je a obvyklé (a často i neobvyklé) věci to umí. Nabízí se ale vtíravá otázka: co když chci vlastní doplňování, které standardně v balíku není? Samozřejmě je možné si napsat vlastní skript. Z toho také ostatně velmi dobře pochopíte, jak celá věc funguje.

Vytvoříme si nový skript, který bude obsluhovat virtuální příkaz pokus. Ten bude mít několik různých parametrů, které si necháme doplnit. Pro funkčnost tohoto příkladu není třeba samotný program pokus vytvářet. Kód bude vypadat takto:

_pokus()
{
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    opts="--help --pomoc --pokracuj --hehehe"

    if [[ ${cur} == -* ]] ; then
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
        return 0
    fi
}
complete -F _pokus pokus

Pokud tento kód vložíte do souboru /etc/bash_completion.d/pokus a znovu se přihlásíte, můžete si nechat doplnit parametry:

$ pokus --h[tab]
--help --hehehe

Můžete si vyzkoušet, že to funguje. Samozřejmě si vysvětlíme celý princip, který je velmi jednoduchý. Jedná se o jednoduchou Bash funkci, jejímž výstupem je proměnná COMPREPLY. To je pole, ve kterém se Bashi vrací odpověď s informací, které parametry jsou v tuto chvíli přípustné.

Samotné doplňování za nás zajišťuje příkaz compgen, který jednoduše vybírá vhodné možnosti z nabízených a ze vstupu, který mu předáme. Můžete si to vyzkoušet na řádce takříkajíc „nasucho“:

$ compgen -W "--help --pomoc --pokracuj" -- "--po"
--pomoc
--pokracuj

Program porovná sadu nabízených variant se zadaným vstupem ( --po) a vypíše možnosti. Zbytek skriptů je už jasný: načteme vstupní hodnoty od Bashe (co zadal uživatel) z pole COMP_WORDS, které obsahuje slova, která jsou právě napsaná na řádce. My si přečteme poslední slovo – proto konstrukce COMP_CWORD-1  – proměnná obsahuje počet slov napsaných právě na řádce. My si tedy zvolíme poslední (tedy nedopsané) slovo. Compgen za nás vybere příslušné možnosti a ty vrátíme Bashi.

Poslední řádek ve skriptu řekne Bashi, že má svázat naši funkci s konkrétním příkazem. Můžeme samozřejmě jednu funkci použít pro více příkazů, pokud by měly stejné parametry nebo by se jednalo o symbolický link na jeden program.

Toto je jen velmi jednoduchá ukázka funkčního skriptu, podle které jste měli pochopit princip. Samozřejmě je možné přejít k podstatně složitějším akcím, kdy můžeme hledat v databázích, zjišťovat něco na internetu (třeba e-mailové adresy v IMAPu a podobně), záleží jen na vašich nápadech.

ict ve školství 24

Pravdou ovšem je, že ve většině případů si vystačíte s doplňováním parametrů z pevného seznamu, pokud máte vlastní skriptíky, můžete se s nimi pochlubit v diskusi.

Další informace naleznete v man bash, kde je popsána i proměnná COMPREPLY.

Autor článku

Petr Krčmář pracuje jako šéfredaktor serveru Root.cz. Studoval počítače a média, takže je rozpolcen mezi dva obory. Snaží se dělat obojí, jak nejlépe umí.