Portál AbcLinuxu, 27. května 2024 02:38

Bash: chytré doplňování

13. 8. 2007 | Michal Vyskočil
Články - Bash: chytré doplňování  

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.

Úvodem

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.

Doplňování v praxi

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.

Jak to funguje

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.

Jak napsat vlastní funkci

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

Související články

Anketa: Jaký je váš výchozí shell?
Seriál: BASH

Odkazy a zdroje

info bash
Bash reference manual
An introduction to bash completion: part 1
An introduction to bash completion: part 2

Další články z této rubriky

Praktický test komprese ZPAQ v programu lrzip
Porovnávání souborů PDF
Microsoft rozdává zadarmo stovky e-knih
Minimalistické prezentace s Markdown
Kde hledat Creative Commons a alternativy

Diskuse k tomuto článku

Limoto avatar 13.8.2007 00:14 Limoto | skóre: 32 | blog: Limotův blog
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
Odpovědět | Sbalit | Link | Blokovat | Admin
tak jak si to rozumí s archem a pacmanem?
13.8.2007 08:50 alium | skóre: 38 | blog: Category 1100
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
umi pracovat s prikazy co jsou v archu a v pacmanovy (nevim ale jestli i s pacmanem 3), maji na to v archu specialni patch.
wamba avatar 13.8.2007 11:30 wamba | skóre: 38 | blog: wamba
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
funguje z pacmanem dobře:

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
This would have been so hard to fix when you don't know that there is in fact an easy fix.
13.8.2007 00:17 phero | skóre: 17 | blog: techblog
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
Odpovědět | Sbalit | Link | Blokovat | Admin
Diky! Doplnovani dela z otravnyho shellu luxusni zalezitost. Jen trakova drobnost. Jak pises jak se tvori vlastni funkce - bylo by hezky krome rozboru toho prikladu to napsat jeste velice strucne obecne.
13.8.2007 05:50 Käyttäjä 11133 | skóre: 58 | blog: Ajattelee menneisyyttä
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
Odpovědět | Sbalit | Link | Blokovat | Admin
1. měl si to napsat dříve, ne až po tom co jsem si svůj první bash_completion skript napsal sám bez znalosti článku :-)
2. o tomhle jsem chtěl napsat článek taky :-)
13.8.2007 08:47 alium | skóre: 38 | blog: Category 1100
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
Odpovědět | Sbalit | Link | Blokovat | Admin
ja jej mel nainstalovany, ale nefungoval.. Az ted jsem se docetl, ze jsem neudelal source /etc/bash_completion. Diky za clanek !
4.9.2007 14:31 polish
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
to je ta psravna informace, dikes
Pavel Dobeš avatar 13.8.2007 10:33 Pavel Dobeš | skóre: 21 | Praha
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
Odpovědět | Sbalit | Link | Blokovat | Admin
No nekdy narazim na nazev souboru, kde doplnovani nefunguje. Kdyz jsou definovane pripony souboru, ktere funguji a ja chci pracovat s nejakou, ktera neni nadefinovana, tak to take nefunguje. Pokud by slo nejak na cas zakazat doplnovani a spolehnout se na jednoduchy TAB, tak by o byla prace s doplnovanim prijemnejsi.
Windows? A kdo to ještě používá?
13.8.2007 12:23 R
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
Typicky priklad: chcem unzipom rozbalit samorozbalovaci EXE subor a ono mi to tam nechce doplnit
13.8.2007 12:33 phero | skóre: 17 | blog: techblog
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
co takle si tu funkce opravit - zabralo by min casu nez jsem psat; a kdyz uz v tom budes tak to muzes dat do upstreamu
Pavel Dobeš avatar 13.8.2007 13:02 Pavel Dobeš | skóre: 21 | Praha
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
Ono protlacit neco do distribuce je opravdu na dlouhe lokte... A upravovat si konfiguraky po kazdem upgrade, to me moc nebavi. Navic nektere ty funkce jsou tak slozite a komplexni, ze odstraneni nejake chyby neni upravou trivialni.
Windows? A kdo to ještě používá?
13.8.2007 13:46 Michal Vyskočil | skóre: 60 | blog: miblog | Praha
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
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 ;-)
When your hammer is C++, everything begins to look like a thumb.
Pavel Dobeš avatar 13.8.2007 14:13 Pavel Dobeš | skóre: 21 | Praha
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
OK, neco opravim, neco nezvladam opravit. Takze po upgrade musim zjistit, co se zmenilo a zda neni nejaka zmena v tom, co jsem upravoval ja (treba upgrade je komplexnejsi, nez moje zmena). Tj po kazdem upgrade musim stejne projit zmeny at to je u me a nebo ne.
Windows? A kdo to ještě používá?
14.8.2007 09:32 R
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
EXE som si tam doplnil. Ale to neriesi problem - niekedy potrebujem unzipom rozbalit subor s nejakou inou priponou. Chcelo by to nejaku klavesovu skratku, ktorou by sa doplnanie docasne preplo do standardneho modu.
14.8.2007 15:35 phero | skóre: 17 | blog: techblog
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
To by se hodilo.
freshmouse avatar 13.8.2007 10:40 freshmouse | skóre: 42 | blog: Bruno Banány
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
Odpovědět | Sbalit | Link | Blokovat | Admin
Mnoho nováčků v Linuxu je znechuceno psaním šílených příkazů jako (...)

Mnoho nováčků je znechuceno psaním příkazů.
13.8.2007 10:58 hikite
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
Mnoho nováčků je znechuceno.
13.8.2007 11:01 thingie
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
Mnoho nováčků je.
junckritter avatar 13.8.2007 12:24 junckritter | skóre: 3 | blog: Laying_Circus | Trnava
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
Mnoho nováčků.
2008 All Human Rights Reserved
13.8.2007 13:28 pexxi
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
Mnoho
freshmouse avatar 13.8.2007 13:29 freshmouse | skóre: 42 | blog: Bruno Banány
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
 
13.8.2007 14:39 Kyosuke | skóre: 28 | blog: nalady_v_modre
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
HY090: Invalid string or buffer length. Length cannot be negative.
13.8.2007 17:01 Creator of Myths
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
xD
13.8.2007 13:45 ls
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
Mnoho
frEon avatar 13.8.2007 14:51 frEon | skóre: 40 | Praha
Rozbalit Rozbalit vše Re: Bash: chytré doplňování
mnoho novacku je nadseno psanim prikazu, nebo bylo (ja) :-)
Talking about music is like dancing to architecture.
13.8.2007 10:40 miro | skóre: 19 | blog: miro
Rozbalit Rozbalit vše doplnanie prikazov spustanych pod sudo
Odpovědět | Sbalit | Link | Blokovat | Admin
Doplnanie v bashi je super vec, akurat v pripade, ked zacnem riadok 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...) ?
13.8.2007 11:13 fakenickname | skóre: 42 | blog: fakeblog
Rozbalit Rozbalit vše Re: doplnanie prikazov spustanych pod sudo
treba sudo bash nebo su ;) ale jinak taky bych rad vedel jak to udelat..
wamba avatar 13.8.2007 11:34 wamba | skóre: 38 | blog: wamba
Rozbalit Rozbalit vše Re: doplnanie prikazov spustanych pod sudo
Nevím jak to docílit, ale mně to funguje :)
This would have been so hard to fix when you don't know that there is in fact an easy fix.
wamba avatar 13.8.2007 11:53 wamba | skóre: 38 | blog: wamba
Rozbalit Rozbalit vše Re: doplnanie prikazov spustanych pod 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
This would have been so hard to fix when you don't know that there is in fact an easy fix.
13.8.2007 19:45 miro | skóre: 19 | blog: miro
Rozbalit Rozbalit vše Re: doplnanie prikazov spustanych pod sudo
Diky. Uz to mam.

Skript /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...
13.8.2007 22:20 fakenickname | skóre: 42 | blog: fakeblog
Rozbalit Rozbalit vše Re: doplnanie prikazov spustanych pod sudo
> cat ~/.bashrc
...
# COMPLETION
source /etc/bash_completion
Limoto avatar 13.8.2007 22:26 Limoto | skóre: 32 | blog: Limotův blog
Rozbalit Rozbalit vše Re: doplnanie prikazov spustanych pod sudo
a nebylo by lepší to udělat rovnou pro všechny uživatele?

# cat /etc/profile.d/bash_completion.sh
#!/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
13.8.2007 22:32 miro | skóre: 19 | blog: miro
Rozbalit Rozbalit vše Re: doplnanie prikazov spustanych pod sudo
> cat ~/.bashrc


# COMPLETION
. /etc/bash_completion

dal som to tam hned, tiez vsetok svoj bordel napcham do .bashrc, aj ten, co by urcite mohol ist niekam inam :)
zoul avatar 15.8.2007 10:39 zoul | skóre: 43 | blog: | Boskovice
Rozbalit Rozbalit vše Rychlost?
Odpovědět | Sbalit | Link | Blokovat | Admin
Chytré doplňování se mi líbí, ale vadí mi, že načítání skriptu pro doplňování tak dlouho trvá. Kdykoliv otevřu nové okno terminálu, je cítit prodleva:

zoul@naima:~$ time bash

real 0m0.720s
user 0m0.533s
sys 0m0.136s

Versus obyčejný bash bez doplňování:

zoul@naima:~$ time bash

real 0m0.041s
user 0m0.007s
sys 0m0.016s

Řešíte to někdo nějak?
15.8.2007 13:17 Michal Vyskočil | skóre: 60 | blog: miblog | Praha
Rozbalit Rozbalit vše Re: Rychlost?
Pokud vím, tak spousta lidí to vyřešila přechodem k zsh :-)
When your hammer is C++, everything begins to look like a thumb.
17.8.2007 16:40 Pavel Francírek | skóre: 6
Rozbalit Rozbalit vše MC v Ubuntu
Odpovědět | Sbalit | Link | Blokovat | Admin
No, to je jedna z mala veci, ktere me na Ubuntu opravdu stvou. Kdyz totiz chci editovat soubor pomoci "mc -e", tak mi to stale (na rozdil od Debianu) nabizi pouze adresare (doplnovani pro mc).
19.8.2007 11:18 Semo | skóre: 45 | blog: Semo
Rozbalit Rozbalit vše Re: MC v Ubuntu
mc -e $1 == mcedit $1
If you hold a Unix shell up to your ear, you can you hear the C.

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.