Hrátky z řádky: Návratové hodnoty

Ondřej Bojar 3. 3. 2008

Opět se setkáváme u pravidelné pondělní dávky tipů a triků z černé řádky. Minulé díly nás naučily přesměrovávat vstupy a výstupy, příkazovou řádku a proměnné do roury a opačně. Dnešní díl se podívá podrobněji na návratovou hodnotu procesu a kombinace procesů právě na základě návratových hodnot.

Dva příkazy za sebou

Filozofii příkazové řádky v Unixu už určitě tušíte: programy jsou stavební kameny, z nichž budujete větší celky. Podobně jako funkce (procedury, rutiny, predikáty, podle vašeho oblíbeného nářečí) pospojované za sebe tvoří program.

Nejsnazší způsob, jak „kombinovat“ dva programy, je spustit jeden a pak druhý. Když to celé chcete zapsat na jednu řádku (a nemačkat Enter/Return) dvakrát, můžete jako oddělovač použít středník:

$ tar czf adresar.tgz adresar; rm -rf adresar
$ # takhle je to ale riskantní! Čtěte dál.

Program tar (výklad mírně kryptických parametrů viz manuálová stránka) zabalí strom adresáře adresar do souboru adresar.tgz. Program rm pak rozbalený originál smaže.

Co když ale tar úkol nezvládne? Třeba když dojde místo na disku… Středník tohle neřeší a po taru prostě spustí mazání.

Konjunkce: Pokračuj jen při úspěchu

Obecně doporučuji na středník (nebo prostý nový řádek ve skriptech) skoro zapomenout a vždy dávat přednost konjunkci &&:

$ tar czf adresar.tgz adresar && rm -rf adresar
$ # takhle ano

Konjunkce bashi nařizuje ověřit návratovou hodnotu taru a spustit rm, jen pokud tar signalizoval úspěch (exit code roven 0).

Disjunkce: Záchranné řešení při neúspěchu

Disjunkce ( ||) se velmi často hodí pro předčasné ukončení skriptu, kde by bylo velmi nepohodlné příkazy stále spojovat pomocí &&. (Skript není nic jiného než textový soubor s řadou příkazů, více si povíme někdy příště.)

$ tar czf adresar.tgz adresar || exit 1
$ # jestli tar selže, ukonči skript
$ rm -rf adresar   # chyba při mazání nám tolik nevadí

Příkaz exit ukončí aktuální shell (tj. v případě skriptu ukončí skript) s udanou návratovou hodnotou. Příklad výše tedy signalizuje neúspěch (exit code 1); exit bez parametru skončí s úspěchem (exit code 0). Podobně jako by vaše prsty měly místo středníku skoro automaticky psát &&, měly by za každý příkaz ve skriptu hned psát exit a nezapomenout jedničku. Jinak si totiž vybudujete sbírku nespolehlivých nástrojů, které vás podrazí v nejméně čekaných chvílích.

Složité sestavy konjunkcí a disjunkcí člověk v praxi většinou nestaví, příliš snadno se v nich lze zamotat a navíc jsou po delší době nečitelné. Tomu, kdo by se do toho přece jen chtěl pustit, připomínám existenci složených závorek pro uzávorkování výrazů. Je ale nutné psát závorky oddělené mezerami a středníkem od okolních příkazů, např.:

$ { { prikaz1 || prikaz2; } && prikaz 3; }; prikaz 4

Spuštění na pozadí

Ukažme si ještě, co způsobí malý překlep: & místo &&:

$ tar czf adresar.tgz adresar & rm -rf adresar
$ # takhle rozhodně ne!!!

Jeden ampersand jako oddělovač příkazů znamená: spusť první, nečekej na nic a hned spusť druhý. Co myslíte, když si komprimace a mazání na vašem počítači dají závody, kdo vyhraje?

Ampersand můžete chápat jako oddělovač příkazů, alternativu ke středníku: středník znamená „spusť jeden po druhém“ ampersand „spusť současně“ Skoro běžnější je ale chápat ampersand jako příznak „spusť na pozadí“ který prostě přidáváte k jednomu příkazu:

$ rm -rf adresar &
$ # tohle mazání poběží dlouho, nechci čekat

Při spuštění na pozadí je trochu nemilé, že se návratová hodnota nenávratně ztratí. O tom, jestli mazání nakonec uspělo nebo ne se dozvíte jen podle hlášky, kterou bash časem po skončení procesu vypíše na konzoli: buď Done nebo Exit. Nijak na ni ale ve skriptu reagovat nemůžete, na to je nutné, aby proces na pozadí před svým koncem návratovou hodnotu na smluvené místo poznamenal.

Jak zjistit návratovou hodnotu

Zatím ale neumíme návratovou hodnotu ani zjistit, natož někam poznamenat. Pojďme to napravit:

$ true; echo $?
$ false; echo $?

Programy true a false mají snadný úkol, jen skončit s příslušnou návratovou hodnotou: true signalizuje úspěch, tj. návratová hodnota 0, false neúspěch, proto 1. Speciální proměnná $? obsahuje návratovou hodnotu posledního příkazu. Schválně, co vypíše dvojice:

$ echo $?; echo $?

Návratová hodnota skriptu na pozadí

Vraťme se k problému, jak neztratit návratovou hodnotu příkazu spuštěného na pozadí. Pro ten účel je nutné spustit na pozadí nejen ten příkaz, o který nám jde, ale po něm ještě uložení návratové hodnoty do souboru. Čili vlastně takový malý skriptík. Dvojici příkazů proto uzavřeme do kulatých závorek, čímž bash poprosíme o spuštění kombinace procesů v samostatném shellu. Ampersand se postará o spuštění na pozadí. (Složené závorky nepouští subshell, nelze je tedy použít pro spuštění na pozadí.)

$ (tar xzf rozbalit.tgz ; echo $? > exit_code_rozbaleni ) &

Až tar archiv rozbalí, a to může být kdykoli později, vznikne najednou soubor exit_code_rozbaleni obsahující návratovou hodnotu taru. Kontrolní otázka: proč jsme použili středník a ne &&?

A co návratová hodnota roury?

Než ukončíme dnešní díl, musím zmínit návratovou hodnotu řady programů spojených rourou. Standardně bash sleduje jen hodnotu posledního z programů, čili např. když soubor.txt.gz nejde rozbalit, „počítání řádek“ přesto uspěje:

$ zcat soubor.txt.gz | wc -l || echo "Problém s počítáním řádek"
$ # o problému s nalezením souboru soubor.txt.gz se skript nedozví

V bashi máte možnost buď studovat speciální proměnnou ${PIPESTATUS[0...n]} (vlastně je to pole, ale o tom zas někdy jindy), nebo nastavit volbu bashe, aby zachovával špatné zprávy:

$ set -o pipefail
$ zcat soubor.txt.gz | wc -l || echo "Nastal problém"
$ # dozvíte se o všech problémech, nalezení souboru i počítání řádek
Našli jste v článku chybu?
Měšec.cz: TEST: Vyzkoušeli jsme pražské taxikáře

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

Lupa.cz: Pokémon GO není jediná rozšířená realita. Co dál?

Pokémon GO není jediná rozšířená realita. Co dál?

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

Ceny PHM v Evropě. Finty na úspory

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

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

120na80.cz: Jaké plavecké pomůcky vaše dítě ochrání?

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

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

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

Podnikatel.cz: Selhala pokladna k EET. Kdo zaplatí pokutu?

Selhala pokladna k EET. Kdo zaplatí pokutu?

Podnikatel.cz: Daň z nemovitosti? Změny budou v říjnu

Daň z nemovitosti? Změny budou v říjnu

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

Polská vejce na českém pultu Albertu

Lupa.cz: IT scéna po brexitu: přijde exodus vývojářů?

IT scéna po brexitu: přijde exodus vývojářů?

Vitalia.cz: Cheese&Chilli: předsudky o nudné britské kuchyni

Cheese&Chilli: předsudky o nudné britské kuchyni

Lupa.cz: Největší pitominy s logem “nyní smart a připojené”

Největší pitominy s logem “nyní smart a připojené”

Vitalia.cz: V dTestu vyhrál levný opalovací krém

V dTestu vyhrál levný opalovací krém

Podnikatel.cz: Od baletu k požární ochraně. A jiné rarity

Od baletu k požární ochraně. A jiné rarity

DigiZone.cz: Test Noxon A560+: kvalitka do vaší věže

Test Noxon A560+: kvalitka do vaší věže

Lupa.cz: Japonská invaze. Proč SoftBank kupuje ARM?

Japonská invaze. Proč SoftBank kupuje ARM?

Lupa.cz: Vodafone umí volání přes Wi-Fi. Z ciziny jako v ČR

Vodafone umí volání přes Wi-Fi. Z ciziny jako v ČR

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

Tahle praktika stála šmejdy přes milion

Vitalia.cz: Nejdůležitější změny v potravinářské novele

Nejdůležitější změny v potravinářské novele

120na80.cz: I tuto vodu můžete pít

I tuto vodu můžete pít