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?
120na80.cz: Jaké plavecké pomůcky vaše dítě ochrání?

Jaké plavecké pomůcky vaše dítě ochrání?

Lupa.cz: Nejslabší LTE ve vlacích je na Moravě

Nejslabší LTE ve vlacích je na Moravě

Měšec.cz: Udali ho na nelegální software a přišla Policie

Udali ho na nelegální software a přišla Policie

Podnikatel.cz: Polská vejce na českém pultu Albertu

Polská vejce na českém pultu Albertu

Podnikatel.cz: Tahle praktika stála šmejdy přes milion

Tahle praktika stála šmejdy přes milion

DigiZone.cz: Android TV: s jakým pracuje rozlišením?

Android TV: s jakým pracuje rozlišením?

DigiZone.cz: Skylink o půlnoci vypnul 12 525

Skylink o půlnoci vypnul 12 525

Vitalia.cz: Paní výčepní: Holka, co mluví chlapům do piva

Paní výčepní: Holka, co mluví chlapům do piva

Měšec.cz: Do ostravské MHD bez jízdenky. Stačí vaše karta

Do ostravské MHD bez jízdenky. Stačí vaše karta

Vitalia.cz: Jak může být v uzenině 150 % masa?

Jak může být v uzenině 150 % masa?

Měšec.cz: TEST: Vyzkoušeli jsme pražské taxikáře

TEST: Vyzkoušeli jsme pražské taxikáře

Podnikatel.cz: Italské těstoviny nebyly k mání, tak je začal vyrábět

Italské těstoviny nebyly k mání, tak je začal vyrábět

DigiZone.cz: Skylink: do pátku může docházet k výpadkům

Skylink: do pátku může docházet k výpadkům

DigiZone.cz: Sat novinky: Skylink skončil s kanály ČT

Sat novinky: Skylink skončil s kanály ČT

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

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

DigiZone.cz: Samsung uvolnil nástroj pro Tizen

Samsung uvolnil nástroj pro Tizen

Vitalia.cz: Bio vejce nepoznají ani veterináři

Bio vejce nepoznají ani veterináři

Vitalia.cz: Signál roztroušené sklerózy: brnění končetin

Signál roztroušené sklerózy: brnění končetin

Podnikatel.cz: 3 velké průšvihy obchodních řetězců

3 velké průšvihy obchodních řetězců

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

Ceny PHM v Evropě. Finty na úspory