Hlavní navigace

Hrátky z řádky: tenký led - skripty generují skripty

Ondřej Bojar

Opět se setkáváme u pravidelné pondělní dávky tipů a triků z černé řádky. Ve většině stávajících dílů jsme se snažili omezit rizika chyb v shellových skriptech. Dnes zmíníme možnosti, jak si naopak efektivně na problém náhodnými překlepy naběhnout. Skripty totiž samozřejmě mohou generovat skripty.

Spusť příkaz – eval

Jsou situace, kdy potřebujete „vypočítat“ název programu, který budete spouštět. (Například při hodně nebezpečné situaci, kdy uživatel zadává vašemu skriptu přímo nějakou výkonnou komponentu.) V některých verzích bashe navíc expanze proměnných neprobíhala v prvním slově příkazové řádky, takže název programu nešlo přímo brát z proměnné. Dnes už bash proměnné expanduje a název programu z proměnné brát můžete, dokonce i s předpřipra­venými počátečními argumenty:

moje_razeni="sort -nr"
$moje_razeni < in > out
# příklad je jen ilustrativní, konkrétně v tomhle případě by
# jistě bylo lepší zadefinovat a užít alias

V souladu s gramatikou bash ale expanduje proměnné až po částečném rozboru příkazové řádky, kdy jsou identifikovány jednotlivé příkazy oddělené středníkem, rourou ap. Když tedy výsledek „výpočtu“ programů (nebo ten vstup od uživatele), který chcete spustit, zahrnuje složitejší konstrukce, nezbývá, než použít explicitní prosbu o vyhodnocení, tj. eval:

moje_razeni="sort -n | tac"
# neznám parametr -r, znám jen tac, opak catu
cat in | $moje_razeni
# nezabere! bash zkouší spustit sort s parametry "-n", "|" a "tac"
cat in | eval $moje_razeni
# zabere, eval obsah proměnné $moje_razeni nechá vyhodnotit na místě,
# tj. stejně, jako kdybyste rovnou napsali
cat in | sort -n | tac

Samozřejmě použití evalu zesiluje vaši povinnost myslet na správné uvozovkování a ochraňování speciálních znaků. Plejáda problémů, na něž můžete narazit, je příliš široká, takže mohu poradit jediné: postupujte po malých krůčcích a testujte každý krok a eval izolovaně, než se přesvědčíte, že na požadovaných vstupech dělá, co má.

Spusť skript v aktuálním shellu – source, tečka

Už dříve jsme vyráběli jednoduché skripty. Ty se spouštěly v samostatném procesu (tj. ekvivalent „/bin/bash nazev_skriptu“), takže nemohly např. nastavit adresář nebo proměnné prostředí tak, aby nastavení zůstalo platné pro náš shell. Pak jsme zmínili aliasy jako prostředek pro spuštění předpřipravené konstrukce v aktuálním shellu.

Kombinaci obojího představuje spuštění skriptu v aktuálním shellu, tzv. sourcnutí. Provedeme jej pomocí příkazu „source“, který se pro zpestření a z historických důvodů dá zkráceně také zapsat jako „.“ (tečka). Nejspíš proto, aby se vám v manuálových stránkách hůře hledalo, co ta tečka dělá…

source muj_skript
# stejně jako
. muj_skript
# spustí muj_skript přímo v aktuálním shellu

Kdy sourcování potřebujete? Kdykoli má skript ovlivnit vaše aktuální prostředí. (Nastavení adresáře, proměnných, aliasů… V tomto smyslu je např. ~/.bashrc také „sourcován“.) Jaká jsou rizika? Velká, sourcnutý skript může omylem poničit vaše (exportované i neexportované) proměnné, zanechat vás v adresáři, se kterým nepočítáte, nebo vám rovnou uzavřít spojení! (Rozhodně neradím napsat „exit“ do vašeho .bashrc.)

Jsem spuštěn, nebo sourcnut?

Právě konfigurační skripty, kterými si má uživatel nastavit nějaké proměnné ve svém prostředí ap., potřebují nutně, aby byly načteny přímo aktuálním bashem, nikoli spuštěny. Vhodné je uživatele o této časté chybě informovat. O detekci se postará následující magická formulka:

if [ -z $BASH_ARGV ]; then
    cat >&2 <<-KONEC
    Tento inicializační skript musíte pro správný běh spustit takto:
      . $0
    tj. v aktuálním shellu a nikoli jako samostatný proces.
    KONEC
    # pozor na to, aby před slovem KONEC byly jen tabulátory, ne mezery
    exit 1
fi

Generuj-kopíruj-vlož

Dnešní celkem stručný díl uzavřu svým oblíbeným tipem pro spouštění mnoha příkazů s různými argumenty najednou. Program xargs v našem seriálu určitě spatříte. Je dobrý, když jste si jisti a chcete všechny příkazy hned spustit (nebo ručně každý potvrzovat, použijete-li „ xargs -p“). Občas se ale hodí hromadu příkazů automaticky připravit a pak spouštět víceméně naráz, jen s lehkou optickou kontrolou, jestli nedělají blbosti, nebo s lehkými pauzami, aby se nějaký systém nezahltil.

V takovém případě často vyrobím např. jednoduchý for-cyklus, který zamýšlené příkazy vypíše na konzoli. Prohlédnu si je a zkusím první zkopírovat a hned vložit, čímž se příkaz spustí. Pokud jsem s výsledkem spokojen, zkopíruju dalších pár příkazů a zas je vložím (možná do jiné konzole, aby mi tahle neodrolovávala). A když vidím, že systém dávku vstřebal, vezmu další.

Když je příkazů prostě moc na ruční copy-paste přes konzoli, použiju generovací for cyklus, ale přesměruji jej do souboru:

(for args in ...; do echo cmd $args; done) > rychloskript.sh

Rychloskript si pak prohlédnu, případně tu a tam vložím „ sleep 5“, aby se prostředí mohlo vzpamatovat, a nakonec spustím „ sh rychloskript.sh“ nebo „ source rychloskript.sh“, podle toho, co potřebuji.

Našli jste v článku chybu?

21. 4. 2008 15:33

Clock (neregistrovaný)
A kde jsou replikatory? A podivne replikatory ktere generuji odlisne kopie sebe sama?

Lidi jsou kvuli replikaci schopny silet lizt po rimsach a okapech, ale kdyz replikace prijde na radu v clanku o skriptech, nic o ni ani nenapisou :)

Je jaro lidi sili...



21. 4. 2008 15:19

Všechny moje skripty, které generují skripty, jsou bohužel tak jednoúčelové, že nestálo za to žádný konkrétní uvádět, a tak jsem uvedl aspoň tu myšlenku. Takže díky za doplnění pěkného příkladu (a vyzývám k příkladům dalším).

A propos, m4. Kdysi pradávno jsem ho taky na něco používal. Nechtěl byste o tom napsat stručný díl? Do základního repertoáru totiž m4 určitě patří.

Vitalia.cz: Jmenuje se Janina a žije bez cukru

Jmenuje se Janina a žije bez cukru

Lupa.cz: Kdo pochopí vtip, může jít do ČT vyvíjet weby

Kdo pochopí vtip, může jít do ČT vyvíjet weby

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

Vitalia.cz: 7 druhů hotových těst na vánoční cukroví

7 druhů hotových těst na vánoční cukroví

Podnikatel.cz: EET: Totálně nezvládli metodologii projektu

EET: Totálně nezvládli metodologii projektu

Měšec.cz: Jak vymáhat výživné zadarmo?

Jak vymáhat výživné zadarmo?

120na80.cz: Na ucho teplý, nebo studený obklad?

Na ucho teplý, nebo studený obklad?

Podnikatel.cz: Chaos u EET pokračuje. Jsou tu další návrhy

Chaos u EET pokračuje. Jsou tu další návrhy

Vitalia.cz: Mondelez stahuje rizikovou čokoládu Milka

Mondelez stahuje rizikovou čokoládu Milka

Vitalia.cz: Jsou čajové sáčky toxické?

Jsou čajové sáčky toxické?

Měšec.cz: Zdravotní a sociální pojištění 2017: Připlatíte

Zdravotní a sociální pojištění 2017: Připlatíte

DigiZone.cz: ČRa DVB-T2 ověřeno: Hisense a Sencor

ČRa DVB-T2 ověřeno: Hisense a Sencor

DigiZone.cz: Rádio Šlágr má licenci pro digi vysílání

Rádio Šlágr má licenci pro digi vysílání

Vitalia.cz: Jedlé kaštany jsou trpké, je třeba je tepelně upravit

Jedlé kaštany jsou trpké, je třeba je tepelně upravit

Lupa.cz: Co se dá měřit přes Internet věcí

Co se dá měřit přes Internet věcí

Lupa.cz: Proč firmy málo chrání data? Chovají se logicky

Proč firmy málo chrání data? Chovají se logicky

Vitalia.cz: Spor o mortadelu: podle Lidlu falšovaná nebyla

Spor o mortadelu: podle Lidlu falšovaná nebyla

Vitalia.cz: Znáte „černý detox“? Ani to nezkoušejte

Znáte „černý detox“? Ani to nezkoušejte

Lupa.cz: Propustili je z Avastu, už po nich sahá ESET

Propustili je z Avastu, už po nich sahá ESET

Měšec.cz: Kdy vám stát dá na stěhování 50 000 Kč?

Kdy vám stát dá na stěhování 50 000 Kč?