<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xml" href="/cjs/screen.xsl" media="screen"?>
<lecture>

<meta>
  <maintitle>Python</maintitle>
  <author>Jiří Znamenáček</author>
  <title>Obsluha externích procesů – „os.system()“</title>
  <date>2011-04-07|2014-08-17</date>
  <link><!--a href="http://vyuka.ookami.cz" rel="external">http://vyuka.ookami.cz</a--></link>
</meta>
<!--
  „“–
  ↵ aneb &#x21B5; aneb \r aneb CR aneb CarriageReturn
-->


<slide title="Úvod">

  <p>
    <code>os.system()</code> je „nejbrutálnější“ a navíc platformně závislý způsob spouštění cizích programů. Při jeho použití jde v podstatě o následující:
  </p>
  <ol>
    <li>
      Python na pozadí otevře zcela nové běhové prostředí (neviditelnou konzoli) v základním nastavení.
    </li>
    <li>
      V tomto nově otevřeném prostředí je zavolán uvedený program.
    </li>
    <li>
      Pokud program skončí svůj běh, je řízení předáno zpět Python'u do původního prostředí.
    </li>
  </ol>
  
  <p>
    PS: Jelikož (nejen) pro spouštění externích procesů je potřebná znalost aktuální pozice v rámci souborového systému, zopakujte si <a href="/materialy/python/modules/os.xml">práci s cestou v rámci modulu <em>os</em></a>.
  </p>

</slide>
<slide title="Omezení">

  <p>
    Jelikož takto spouštěný program „běží“ ve zcela jiném a na originále nezávislém prostředí, nese s sebou použití metody <em>os.system()</em> spoustu omezení:
  </p>
  <ul>
    <li>
      Prostředí spuštěné na pozadí má základní nastavení a naprosto nic nepodědí z případných změn provedených v prostředí, ve kterém jste volali původní pythoní program.
      <note>Tudíž případná potřebná nastavení je potřeba zařídit jinak, například pomocí parametrů volaného programu (jde-li to).</note>
    </li>
    <li>
      Úplně stejný problém máme při návratu – spouštěcí pythoní skript neví o případných výstupech volaného programu vůbec nic, takže předávání výsledků (je-li potřeba) musíme zařídit jinak.
      <note>Specificky se třeba nemáme dost dobře šanci dozvědět, že volaný program zhavaroval. Pokud si při jeho volání nepřesměrujeme chybový výstup a po návratu ho neprozkoumáme.</note>
    </li>
    <li>
      Pokud se externí volaný program na něčem zadrhne a zacyklí, jsme v podstatě „nahraní“.
    </li>
  </ul>

</slide>
<slide title="Základní použití">

  <p>
    Použití <em>os.system()</em> je ve většině případů extrémně jednoduché:
  </p>
  <blockquote>
    <code>os.system(PŘÍKAZ)</code>
  </blockquote>
  <p>
    ..kde <em>PŘÍKAZ</em> je <em>řetězec</em> obsahující kód pro příkazovou řádku, který chceme zavolat.
  </p>
  
  <p>
    Zkusme pro ukázku zavolat nějaký systémový program, např. <em>ls</em> (s uvedenou adresářovou strukturou):
  </p>
  <example layout="horizontal">
    <in src="_files/execution/ls.test.in" lang="text"/>
    <program src="_files/execution/ls.test.py" lang="python"/>
    <out src="_files/execution/ls.test.out" lang="text"/>
  </example>
  <notes>
    <note>
      Výstup programu směřuje na aktuální <em>sys.stdout</em>, čili nejspíš na terminál.
    </note>
    <note>
      Typicky takto můžete použít pythoní skripty pro řízení běhu sady složitějších skriptů, které je třeba vykonat v uvedeném pořadí (aniž byste museli třeba zrovna sedět pod UNIXem a psát v bashi), například:
      <example lang="python">
        os.system( "saxon -o example.html example.xml example.xslt" )
      </example>
    </note>
  </notes>

</slide>
<slide title="Ošetření výstupů">

  <p>
    Ve své přímočarosti <code>os.system()</code> „kašle“ na jakékoli změny v prostředí (např. <em>sys.stdout</em> a další), musíme se k němu tedy opravdu chovat, jako kdybychom příslušný program spouštěli přímo na vlastní příkazové řádce.
  </p>
  <p>
    Třebas výstup příkazu <code>ls</code> z předchozího příkladu si můžete přesměrovat do externího souboru..
  </p>
  <example lang="python">
    os.system( "ls >listing.txt" )
  </example>
  <p>
    ..odkud ho pak normálně pomocí <em>with open()</em> přečtete a dále zpracujete.
  </p>

</slide>
<slide title="Ošetření chyb">

  <p>
    A to samé se týká ošetření havárií a chybových hlášení volaného programu – prostě je přesměrujte do vlastního souboru..
  </p>
  <example lang="python">
    os.system( "ls 1>listing.txt 2>listing_errors.log" )
  </example>
  <p>
    ..a následně pomocí <em>with open()</em> zpracujte.
  </p>

</slide>
<slide title="Bezpečnostní upozornění">

  <p class="security">
    Je vidět, že <code>os.system()</code> je celkem slušná bezpečnostní díra – cokoliv do něj pošlete, bude operačním systémem slepě vykonáno. A pošlete-li tam něco „ošklivého“, nedejbože z Python'u s vyššími právy, než měl mít, máte hodně velký problém.
  </p>
  <p>
    Ostatně dnes už máme k dispozici lepší způsoby, <a href="execution_subprocess.xml">jak volat externí program</a>. (Ale i ty skrývají podobné bezpečnostní zádrhele, jen nejsou takhle úplně volně dostupné.)
  </p>

</slide>
<slide title="Další možnosti">

  <p>
    Asi je vám už celkem jasné, že <em>os.system()</em> nebudete používat zrovna často. Ale kdyby přece, dává Python (především z historických důvodů) k dispozici ještě několik dalších nástrojů podobného ražení, především rodinu metod <em>os.popen</em>, <em>os.spawn</em>, <em>os.exec</em> a modul <em>popen2</em>.
  </p>
  <handout>
    Mezivarianty: os.popen(), os.popen2(), os.popen3(), popen2.XX, os.spawnXX(), os.execXX()
  </handout>

</slide>


</lecture>
