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

Ondřej Bojar 21. 4. 2008

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?
DigiZone.cz: Skylink přidává kanály už teď

Skylink přidává kanály už teď

DigiZone.cz: Náhrada za nevrácená zařízení?

Náhrada za nevrácená zařízení?

Měšec.cz: Cestujte bez starostí, získejte výhodné pojištění

Cestujte bez starostí, získejte výhodné pojištění

Vitalia.cz: 5 porcí ovoce a zeleniny: no ale jak na to?

5 porcí ovoce a zeleniny: no ale jak na to?

Root.cz: Quake slaví 20 let novou epizodou zdarma

Quake slaví 20 let novou epizodou zdarma

Podnikatel.cz: "Okurku" vyřeší slevové servery. Už jim věřte

"Okurku" vyřeší slevové servery. Už jim věřte

DigiZone.cz: ČTÚ květen: rušení TV vysílání narůstá

ČTÚ květen: rušení TV vysílání narůstá

Měšec.cz: Od kdy musí studenti platit pojistné?

Od kdy musí studenti platit pojistné?

Root.cz: Špína v počítačích: mrtvé myši, prach a pavouci

Špína v počítačích: mrtvé myši, prach a pavouci

DigiZone.cz: Skylink zapojil nový transpondér

Skylink zapojil nový transpondér

DigiZone.cz: TV Nova a její postoj k DVB-T2

TV Nova a její postoj k DVB-T2

Lupa.cz: Na základně u Dobříše se rozjel 3D tisk z kovu

Na základně u Dobříše se rozjel 3D tisk z kovu

Podnikatel.cz: Eseróčko vs. živnost. Co vyhrává?

Eseróčko vs. živnost. Co vyhrává?

Měšec.cz: Co s reklamací, když e-shop krachuje?

Co s reklamací, když e-shop krachuje?

DigiZone.cz: Roční bonus pro Dvořáka schválen

Roční bonus pro Dvořáka schválen

Vitalia.cz: Máte chutě? Nejezděte do světa, ale do Dobřichovic

Máte chutě? Nejezděte do světa, ale do Dobřichovic

Root.cz: Střílejte v obýváku, stačí kamera a projektor

Střílejte v obýváku, stačí kamera a projektor

Měšec.cz: Ceny PHM v Evropě. Finty na úspory

Ceny PHM v Evropě. Finty na úspory

Root.cz: Nejvýkonnější počítač mají v Číně, podívejte se

Nejvýkonnější počítač mají v Číně, podívejte se

Vitalia.cz: Epidemie: Klíšťová encefalitida po ovčím sýru

Epidemie: Klíšťová encefalitida po ovčím sýru