Komunikace s příkazovým interpretem a ostatními procesy

Existuje řada úloh, které samotný Perl vyřešit neumí a je třeba použít externí příkazy či programy.

Použití funkce system

Funkce system umožňuje provést externí příkaz a zjistit návratovou hodnotu z tohoto příkazu. Nejprve je pomocí funkce fork vytvořena kopie aktuálního procesu, funkcí exec je tato kopie přepsána kódem příkazu, který chceme spustit, skript pak čeká na ukončení tohoto procesu, vrátí jeho návratovou hodnotu a pak je řízení předáno zpět aktuálnímu skriptu. Nulová hodnota znamená úspěch, nenulová hodnota indikuje chybu při provádění tohoto příkazu.

system 'whodo';

Případná chyba vzniklá při spuštění tohoto příkazu nemá vliv na chod aktuálního skriptu v tom smyslu, že by způsobila jeho ukončení. Chceme-li zjistit, jak skončilo volání tohoto příkazu, můžeme zkontrolovat jeho návratovou hodnotu.

$navratova_hodnota = system 'whodo';
print "Volání whodo selhalo" if $navratova_hodnota;
print "Volání whodo proběhlo v pořádku" unless $navratova_hodnota;

# nebo
system 'whodo' or die 'Není možné spustit příkaz whodo';

Příkaz spouštěný pomocí system samozřejmě nemusí být znám v době spouštění skriptu, ale může být znám až při běhu skriptu.

while (1) {
     # načteme jméno příkazu
     chomp ($prikaz = <>);
     
     # až bude zadán řetězec 'konec', skončíme
     last if $prikaz eq 'konec';
     
     # provedeme externí příkaz
     system $prikaz;
}

Proces spuštěný pomocí funkce system zdědí po aktuálním skriptu vlastnosti prostředí. To znamená, že zdědí standardní vstup, standardní výstup, standardní chybový výstup, proměnné prostředí, aktuální adresář či číslo uživatele.

Funkce system neumí získat výstup z takto spuštěného programu, ale je možné využít mechanismy příkazového řádku, pomocí kterých lze tohoto dosáhnout. Takovými mechanismy jsou např. přesměrování či použítí roury.

system 'whodo > whodo.txt';  # výsledek se uloží do souboru
system 'whodo | lpr';        # výsledek se pošle na tiskárnu

Externí programy spouštené funkcí system mohou jako příkazy spouštěné z příkazového řádku dostávat argumenty, je možné spouštět několik procesů po sobě či spouštět procesy na pozadí.

# spuštění více příkazů
system 'cd; echo "adresář změněn"; pwd';

# spuštení příkazu na pozadí
system 'whodo &';

Chceme-li spustit program s argumenty, existují dva způsoby, jak toho dosáhnout. První způsob je předat funkci system v jednom řetězci jméno programu včetně argumentů.

system 'ls -la /home/darena/';

Druhým způsobem je předat funkci system seznam, kde prvním prvkem je jméno externího programu a dalšími prvky jsou argumenty, které budou v nezměněném pořadí předány příslušnému programu.

system 'ls', '-la', '/home/darena/';

Použití funkce exec

Dalším způsobem, jakým dosáhnout spuštení externího programu, je místo funkce system použít funkci exec. Tato funkce je zahrnuta i v mechanismu spouštění programů funkcí system. Používá se k přepsání kódu aktuálního procesu kodém nového programu. Proto při použití této funkce je aktuální perlový skript přepsán a není mu možné předat zpět řízení. Je-li přece jenom řízení předáno zpět původnímu skriptu, došlo k chybě při volání tohoto příkazu.

Operátor obrácené apostrofy

Operátor obrácené apostrofy nebo qx// slouží k provedení externího příkazu pomocí příkazového interpretu a k zachycení jeho standardního výstupu. To bylo při použití funkcí system či exec nemožné.

Návratovou hodnotou tohoto operátoru je výstup ze spuštěného programu. Chybový výstup není zachytáván, ale je možné použít mechanismu shellu pro přesměrování chybového výstupu na standardní výstup.

$obsah = `ls /home/darena`;

# zachytává se i chybový výstup
$obsah = `ls /home/darena 2>&1`;

# chybový výstup nás nezajímá
$obsah = `ls /home/darena 2>/dev/nul`;

Při použití tohoto operátoru se načte celý výstup z externího programu, je pro něj alokována paměť a tento obsah je vrácen. Podle kontextu, ve kterém je operátor použit se vrátí buď jeden řetězec, který obsahuje celý výstup (obsahuje i případné znaky konce řádků), nebo seznam obsahující výstup rozdělený podle hodnoty obsažené v proměnné $/ (nejčastěji to bude znak konce řádku). V případě neúspěchu je vrácena nedefinovaná hodnota nebo prázdný seznam.

Proto není vhodné používat tento operátor pro spouštění programů, u kterých nás nezajímá jejich výstup -- např. kopírování či mazání souborů, změna aktuálního adresáře apod. Pro tyto případy je vhodnější použít funkci system.

Návratová hodnota z provedeného externího příkazu je uložena v proměnné $?. Proto pro zjištění, zda příkaz proběhl úspěšně, použijeme hodnotu této proměnné.

$obsah = `ls /home/darena/kniha`;
print "Výsledek příkazu: $?";      # vytiskne '0'
# $obsah obsahuje 'perl.tex   perl.sty'

$obsah = `ls /home/darena/knihaxxx`;
print "Výsledek příkazu: $?";      # vytiskne '256'

Úplné řízení procesů

Pomocí funkce fork můžeme vytvořit kopii aktuálního skriptu. V ten okamžik běží dva identické skripty. Abychom rozlišili, zda jsme skript rodičovský nebo potomek, využijeme návratovou hodnotu funkce fork. Nulová hodnota je vrácena pro potomka, nenulová pro rodiče.

my $cislo_procesu = fork;
if ($cislo_procesu) {
    # jsme rodič

} else {
    # jsme potomek

}

Po vytvoření nového procesu může dojít k přepsání jiným procesem. K tomu slouží funkce exec s parametrem, kterým je jméno nového programu, kterým proces přepíšeme. V rodičovském procesu můžeme počkat na ukončení potomků pomocí funkce wait. Chceme-li čekat na ukončení konkrétního potomka, použijeme waitpid.

my $cislo_procesu = fork;
if ($cislo_procesu) {
    # jsme rodič

    wait;  # čekáme na ukončení potomka
} else {
    # jsme potomek

    # spustíme externí příkaz
    exec 'externi prikaz';

    # ukončíme tento proces, dál bude probíhat pouze rodič
    exit; 
}
© 2003, František Dařena

Valid XHTML 1.0! Valid CSS!