Portál AbcLinuxu, 30. dubna 2025 08:08
Je obecně známým faktem, že unixové shelly zvládají doplnit název souboru či adresáře. Ty lepší z nich dokáží nejen to, ale i doplnit parametry příkazů, nebo dokonce jejich hodnoty. Díky bash-completion se k nim může řadit i bash, nejpoužívanější shell v Linuxu.
Mnoho nováčků v Linuxu je znechuceno psaním šílených příkazů jako
tar -xzf foo_bar-4.1.76-r2.i386.tar.gz
protože opsat název balíčku správně je otročina a začnou nadávat na to, jak je Linux složitý. Ovšem pokud přijdou na to, že stačí napsat tar -xzf
a stisknout Tab, tak jim shell automaticky doplní zbytek názvu souboru a Linux se stane o něco příjemnějším pracovním nástrojem. Ovšem bash (nemluvě o tcsh nebo zsh) toho umí daleko více.
Upozornění: následující příklady očekávají readline s volbou set show-all-if-ambiguous on
, to znamená, že se možnosti objeví už po prvním stisku klávesy Tab. Zkontrolujte svůj .inputrc
nebo /etc/inputrc
, pokud to chcete mít stejně.
Existuje adresář a v něm následující soubory:
$ ls -1 foo_bar-4.1.76-r2.i386.tar.gz foo_bar-4.1.76-r2.i386.tar.bz2 foo_bar-4.1.76-r2.i386.tar.gz.md5 foo_bar-4.1.76-r2.i386.pdf
Po napsání tar -xzf
bash doplní jen soubor s příponou tar.gz a nebude nabízet pdf, či tar.bz2 soubor. Po napsání tar -xjf
zase nabídne pouze soubor .tar.bz2.
Jak je psáno v článku Příkazový řádek - přítel nejvěrnější od pana Pavla Satrapy - bash od verze 2 nabízí příkaz complete
, který dokáže ovládat doplňování jmen. Není nutné jej nějak moc ovládat. Snad jen to, že příkaz complete
bez parametrů vypíše aktuální nastavení (pro roota nebývá, alespoň v Debianu, nastaveno nic). Příklady jeho použítí najdete ve zmiňovaném článku.
Příkaz complete (bez použití funkcí z bash-completion) umí takzvané základní doplňování:
Ovšem na dnešních systémech se používá programovatelné doplňování, třeba pro příkaz tar
. Pro dpkg
(bere jen argumenty s koncovkou deb
) vypadá nastavení takto:
$ complete | grep dpkg$ complete -o filenames -F _dpkg dpkg
Což je odlišné od complete -A file -X '!*.deb' dpkg
, které by odpovídalo příkladům uvedeným v článku.
Dnešní bash už dokáže nejen doplňovat názvy souborů či adresářů nebo filtrovat výsledky podle koncovky, ale jeho možnosti jsou plně programovatelné, což je ostatně vidět na výše odkazovaném příkladu s programem tar. Kompletní doplňování pak může vypadat např. takto (pro přehlednost uvádím doplněný příkaz na novém řádku):
$ tar [TAB] A c d r t u x $ tar xjf [TAB] $ tar xjf foo_bar-4.1.76-r2.i386.tar.bz2
Pro tar je podpora doplňování nedokonalá, ale uživatelé Debianu si ji mohou "užít" například v programu aptitude
(pravděpodobně stejně to bude fungovat i pro apt-get
). Uživatelé ostatních distribucí nechť v diskusi oznámí, zda a jak to umí i ta jejich.
$ apti[TAB] $ aptitude se[TAB] $ aptitude search foo[ENTER] ... $ aptitude in[TAB] $ aptitude install foom[TAB] $ aptitude install foomatic-[TAB] foomatic-bin foomatic-db-engine foomatic-db-gutenprint foomatic-filters foomatic-gui foomatic-db foomatic-db-gimp-print foomatic-db-hpijs foomatic-filters-ppds
Bash tedy dokáže nejen doplnit název příkazu nebo parametry, ale navíc dokáže doplňovat i ze seznamu dostupných balíčků, což je vlastnost, která se už bez nějakého toho programování neobejde. Z bezpečnostních důvodů ovšem nejsou podobné "legrácky" povoleny uživateli root, takže zmíněné doplňování si mohou užít pouze běžní uživatelé.
Možným řešením je vytvořit speciální účet s minimálními právy a tyto příkazy pak spouštět pomocí sudo. Protože doplňování běží pod aktuálním uživatelem, není třeba se bát o bezpečnost systému, root do procesu vstoupí až po potvrzení (doslova vložení) příkazu.
Klíčem ke všemu je soubor /etc/bash_completion
(resp. soubory v adresáři /etc/bash_completion.d/
pro každou aplikaci zvlášť), což není nic jiného, než shellový skript, takže, pokud doplňování nefunguje, stačí napsat
source /etc/bash_completion
Pokud jej nemáte, tak se podívejte po balíčku s názvem bash-completion. Počet příkazů, kterým bash umí "napovídat", je velký. Pro konkrétní číslo se se stačí podívat.
cat /etc/bash_completion /etc/bash_completion.d/* | grep ^_ | wc -l
Ve výše zmíněném příkladu s dpkg
(complete -o filenames -F _dpkg dpkg
) je důležitý parametr -F
, který volá obslužnou funkci _dkpg
. Tu shell po stisknutí tabulátoru volá a ta má na svědomí ono doplňování parametrů. Pro výpis aktuálních funkcí stačí napsat set | less
.
Kostra doplňovací funkce vypadá takto:
1 _foo() 2 { 3 local cur prev opts 4 COMPREPLY=() 5 cur="${COMP_WORDS[COMP_CWORD]}" 6 prev="${COMP_WORDS[COMP_CWORD-1]}" 7 opts="--ham --spam" 8 9 if [[ ${prev} != -* ]] ; then 10 COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) 11 return 0 12 fi 13 }
a nastavení shellu complete -F _foo foo
. Jméno funkce bývá stejné jako příkaz, který doplňuje, ale není to pravidlem (viz třeba _known_hosts
). Dobrým zvykem bývá tyto funkce uvozovat podtržítkem.
Na řádku tři se pouze vytvoří lokální proměnné cur
, prev
a opts
. COMPEREPLY
je potom výstupní pole, z něhož čte bash jednotlivé možnosti. COMP_WORDS
je speciální proměnná obsahující už napsané znaky, takže na řádku 5 se do proměnné cur
uloží poslední napsané slovo a do prev
to předposlední. COMP_CWORD
tedy není nic jiného, než index do pole COMP_WORDS
. Bash tyto proměnné naplňuje pouze pro funkce, které jsou volány příkazem complete
.
Proměnná opts
(řádek 7) potom obsahuje parametry hypotetického příkazu foo
. A na řádku 9 je podmínka, která zařídí spuštění funkce pro doplnění jen v případě, že poslední napsané slovo nezačíná pomlčkou a řádek 10 je nejdůležitější, protože volá příkaz compgen
, který dokáže vygenerovat ze zadaných možností seznam nabízených hodnot. ten funguje následovně.
$ compgen -W "--foo --bar" -- --f --foo $ compgen -W "--foo --bar" -- -- --foo --bar
Po vytvoření příkazu foo
(a aktivaci doplňování) je potom možné psát
$ foo [TAB] --ham --spam $ foo --h[TAB] $ foo --ham
pacman -
[Tab]
--add --help --remove --upgrade -A -Q -S -V
--freshen --query --sync --version -F -R -U -h
pacman -S pac
[Tab]
pacbuild pacman paco
source /etc/bash_completion
. Diky za clanek !
A upravovat si konfiguraky po kazdem upgrade, to me moc nebavi.A právě proto Bůh stvořil lokální konfiguraci a
/etc/skel
, takže konfigurovatelnost unixů je nezávislá na výchozím nastavení, nebo upgradu systému HY090: Invalid string or buffer length. Length cannot be negative.
sudo
, tak uz sa dalej doplnaju len nazvy suborov, popr. adresarov.
Neviete niekto ako docielit, aby sa po tomto prikaze doplnal aj nazov dalsieho prikazu (chcem napr. napisat sudo callsomelooongcommand blabla a nazov callsomelooongcommand musim vypisat rucne, alebo najprv pripravit zvysok prikazu a potom sa vratit na zaciatok a dopisat sudo...) ?
complete |grep sudo
my vypíše:
complete -o filenames -F _root_command sudo
asi do /etc/bash_completion
stačí přidat:
_root_command()
{
PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin _command $1 $2 $3
}
complete -F _root_command $filenames sudo fakeroot really
/etc/bash_completion
sice mam, su tam aj riadku ktore si uviedol, ale dany skript sa automaticky nikde nespusti. Staci ho zavolat a vramci daneho shellu uz potom doplnovanie funguje pekne. Takze uz ho len strcit niekam kde sa bude volat automaticky...
> cat ~/.bashrc ... # COMPLETION source /etc/bash_completion
#!/bin/bash # # /etc/profile.d/bash-completion # # check if we use bash if [ $SHELL = "/bin/bash" ]; then bash=${BASH_VERSION%.*}; bmajor=${bash%.*}; bminor=${bash#*.} if [ -n "$PS1" ] && [ \( $bmajor -eq 2 -a $bminor '>' 04 \) -o $bmajor -ge 3 ] \ && [ -f /etc/bash_completion ]; then # interactive shell # Source completion code . /etc/bash_completion fi unset bash bmajor bminor fi
> cat ~/.bashrc # COMPLETION . /etc/bash_completiondal som to tam hned, tiez vsetok svoj bordel napcham do .bashrc, aj ten, co by urcite mohol ist niekam inam :)
zoul@naima:~$ time bash
real 0m0.720s
user 0m0.533s
sys 0m0.136s
zoul@naima:~$ time bash
real 0m0.041s
user 0m0.007s
sys 0m0.016s
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.