Skriptování v Bournově shellu/Spouštění příkazů
◄ Skriptování v Bournově shellu/Srovnání shellů | Spouštění příkazů | Skriptování v Bournově shellu/Prostředí ► |
Než se pustíme do zkoumání všech možností Bournova shellu a způsobu, jak jeho sílu využívat, musíme si uvést základy: řekneme si tedy, jak zadat shellu příkazy, aby je provedl.
Snadný způsob: interaktivní sezení
editovatJiný pohled na to, co už jste asi viděli
editovatPokud máte přístup k nějakému un*xovému stroji (nebo k emulátoru un*xového systému v jiném operačním systému), pravděpodobně už Bournův shell — nebo některý z něj odvozený shell — používáte, byť možná nevědomky. Překvapení: už vlastně v shellu skriptujete!
Ve svém Un*xu si sedněte k terminálu; ať už k terminálu jako okenní aplikaci (pokud používáte X Window System, hledejte zkrátka nějaký program s jménem terminal, xterm, rxvt nebo něco podobného), nebo k textové přihlašovací konzoli. Měli byste se ocitnout na příkazovém řádku zhruba této podoby:
Pepa_Kutil:Super_stroj:~>_
případně podoby s nějakým poučením ve stylu
Správce všem vzkazuje: PŘESTAŇTE SE POKOUŠET SHODIT SYSTÉM!
Užijte si tu!
bzt:Jiny_Komp:~>_
nebo naopak strohé podoby ve stylu
$_
Tak to je on. Váš shell, váš přímý přístup ke všemu, co může operační systém nabídnout.
Používání shellu interaktivním způsobem
editovatKonkrétněji, právě spuštěný program je váš shell běžící v interaktivním režimu: Tedy shell, který zobrazuje prompt a kurzor (obvykle blikající záležitost) a čeká, až mu zadáte příkaz, který by mohl vykonat. V interaktivním režimu zadáte příkaz tak, že jej napíšete a odešlete klávesou Enter. Shell pak příkaz předžvýká pro operační systém a svěří kontrolu operačnímu systému, který se postará o další práci. Můžete si povšimnout, že když je předáno řízení, kurzor dočasně zmizí a nelze nic psát (v tento okamžik totiž nemá Bournův shell nad terminálem kontrolu, neboť ji předal spouštěnému programu). Později, až prováděný program skončí svou práci a předá řízení zpět shellu, zobrazí shell nový prompt a kurzor a opět bude čekat na další příkaz. Zkuste to: zadejte příkaz
$ ls enter
Za okamžik se vám zobrazí výpis souboru v pracovním adresáři (tedy adresáři, který shell považuje za „současný“ adresář), nový prompt a kurzor.
To je ten nejjednodušší způsob zadávání shellových příkazů: zkrátka je píšete jeden po druhém a vždy musíte čekat, než předchozí úloha skončí. Shell je tímto způsobem využíván velmi často, ať už už pro provádění příkazů, které patří mezi ty, jež provádí sám Bournův shell, nebo prostě pro spouštění jiných programů (jako například programu ls v příkladu výše).
Užitečná poznámka
editovatNež se pohneme dál, zmíníme se ještě o užitečných klávesových zkrátkách využitelných v interaktivním shellu: jedna bude ukončovat běžící programy nebo příkazy shellu a druhá ukončí shell samotný (nicméně je otázkou, proč byste kdy chtěli přestat používat shell …)
Abyste zastavili běžící program nebo shellový příkaz, zmáčkněte najednou klávesy Control a C. Co se přesně stane, to si povíme v pozdější kapitole, ale prozatím si zapamatujte, že tímto způsobem můžete přerušit úlohy.
Abyste opustili aktuální sezení shellu, zmáčkněte klávesy Control a D. Tahle kombinace kláves vloží znak konce souboru — někdy později si povíme, proč tento znak ukončí aktuální sezení. V některých moderních shellech je tato kombinace kláves potlačena a k ukončení shellu slouží příkaz „exit“. Pokud používáte nějaký z těchto shellů, tak napište slovo „exit“ (jako jakýkoliv jiný příkaz) a zmáčkněte klávesu Enter (počínaje tímto okamžikem už přestaneme mačkání Enteru zmiňovat a budeme je považovat za automatické).
Jen mírně složitější způsob: skript
editovatJak jsme viděli v minulé podkapitolce, spuštěním interaktivního shellu a zadáváním příkazů lze snadno spouštět jednotlivé programy za libovolným účelem. Občas se ale stane, že máte skupinu příkazů, které často opakujete, a to v různých okamžicích a různých sezeních. V programátorsky orientovaném prostředí un*xových systémů samozřejmě existuje způsob, jak dosáhnout stejného výsledku bez opakovaného vypisování příkazů — můžete si napsat program (třeba v Céčku). Ale nebylo by nejsnazší, kdyby shell prostě uměl „přehrát“ seznam příkazů? Kdyby psaní dávek příkazů bylo stejně snadné jako zadávání v interaktivním shellu?
Shellový skript
editovatNaštěstí tu taková možnost skutečně je: Bournův shell má i neinteraktivní režim. V tomto režimu nevypisuje shell žádný prompt a nečeká na příkazy. Místo toho čte příkazy z textového souboru (který shell instruuje podobně, jako scénář říká herci, co má hrát — proto se takovým souborům říká scénáře, respektive (z angličtiny) skripty). Takový soubor obsahuje posloupnost příkazů, úplně stejnou, kterou byste zadali na příkazový řádek interaktivního shellu. Shell čte soubor odshora dolů a ve stejném pořadí provádí příkazy.
Napsat shellový skript je velmi snadné; můžete použít textový editor dle vlastní libosti (nebo dokonce nějaký textový procesor typu LibreOffice Writer, ale nesmíte pak zapomenout uložit program jako prostý textový soubor). Můžete psát příkazy přesně tak, jak byste je psali v prostředí interaktivního shellu. A skript můžete spustit v okamžiku uložení; není zde žádná potřeba překladádání překladačem nebo něčeho podobného.
Pouštění skriptu
editovatAbyste shellový skript spustili (tedy abyste přiměli shell začít soubor číst a provádět v něm obsažené příkazy), napíšete v interaktivním shellu patřičný příkaz, stejně jako kdybyste spouštěli něco jiného (a pokud používáte grafické uživatelské rozhraní, můžete možná shellový skript spustit i kliknutím myší na ikonku skriptu). Nehraje roli, že spouštěný příkaz je opět shell. Například pokud byste chtěli spustit skript MyScript, napíšete v interaktivním shellu (za předpokladu, že soubor skriptu je v aktuálním adresáři):
$ sh MyScript
Zpočátku se vám může zdát podivné, že spouštíte ze shellu shell, ale když se nad tím zamyslíte, dává to smysl. Koneckonců, své příkazy píšete v shellovém sezení v interaktivním režimu. Aby mohl být skript interpretován, spustíte jiný shell v neinteraktivním režimu. To je přesně to, co dělá příkaz výše. Můžete si povšimnout, že Bournův Shell dostává v příkazu výše jediný parametr: jméno skriptu, který má vykonat.
Pokud používáte shell kompatibilní s normou POSIX 1003.1, můžete také spustit neinteraktivní sezení shellu, které provede jediný příkaz. K tomu slouží přepínač -c, který dá shellu najevo, že dalším parametrem není jméno skriptu, ale přímo příkaz:
$ sh -c ls
Později se dostaneme k důvodům, proč byste mohli chtít dělat něco takového (místo prostého zadání příkazu).
Další možností je nechat skript provádět přímo interaktivním shellem: napíšete zvláštní příkaz mající podobu osamocené tečky a po něm (oddělené mezerou) jméno skriptu:
$ . MyScript
Rozdíl mezi použitím tečky a příkazu sh je v tom, že příkaz sh spouští nový proces a tečka nikoliv. Podrobněji si z toho plynoucí rozdíly rozebereme později.
Jiný způsob spuštění skriptu
editovatJe zde ještě další způsob spouštění skriptu, totiž využítí un*xového příznak spustitelnosti. V Unixu má každý soubor trojici příznaků nastavení přístupových práv (pro čtení, pro psaní, pro spouštění), které jsou nastavitelné pro tři různé skupiny uživatelů: Pro uživatele vlastnícího soubor, pro skupinu, ke které program patří, a pro zbytek uživatelů. Pokud zadáte v interaktivním shellu příkaz:
$ ls -l
uvidíte přístupová práva pro všechny soubory v pracovním adresáři (je to sloupec se třemi písmeny, kde r značí čtení, w zápis a x spouštění, trojice práv uživatele je následována trojicí práv skupiny a trojicí práv zbylých uživatelů). Pokud má některá z entit povolené spouštění, pak patřičný uživatel může spouštět skript stejně jako spustitelné programy. Abyste udělali skript spustitelným kýmkoliv, použijte příkaz:
$ chmod +x jméno_skriptu
tedy například
$ chmod +x MyScript
Takový skript pak už lze spustit (pokud je v adresáři zmíněném v proměnné PATH, která obsahuje seznam adresářů, kde je hledán spustitelný program, pokud není explicitně řečeno, kde se nalézá) příkazem:
$ MyScript
Pravděpodobnější ovšem je, že máte skript uložený v adresáři, který v proměnné PATH není. Pak musíte zadat při spouštění i cestu. Tedy pokud je skript v pracovním adresáři, pak jej můžete zkusit spustit příkazem
$ ./MyScript
Po zadání příkazu operační systém umístí soubor do paměti, prozkoumá jej a pokusí se jej spustit. Samozřejmě, jenom některé soubory dávají smysl coby program. Binární soubor nemusí být souborem strojových instrukcí interpretovatelných procesorem. Aby šly naše skripty, které nejsou standardními binárními programy, spustit tímto způsobem, musíme udělat ještě něco navíc.
Jak už jsme zmínili, operační systém soubor nejprve zkoumá. Pokud se jedná o textový soubor, který nejde jen tak předhodit procesoru, pak bude operační systém na prvním řádku očekávat informaci o tom, jakému interpretu má program předhodit. Očekávaný formát skriptů v un*xových systémech je:
#!''jméno a úplná cesta k interpretu''
V našem případě by měla na všech Un*xech fungovat takovýto první řádek:
#!/bin/sh
Tedy skript má být interpretován Bournovým shellem, který je v adresáři bin (přičemž bin sám je v kořenovém adresáři). Například:
#!/bin/sh
echo Ahoj, světe!
Pouštění skriptů tímto posledním způsobem má několik výhod. Za prvé je pohodlnější, protože opakované spouštění vyžaduje nejméně psaní. Za druhé, je bezpečnější, zvláště pokud se chcete o svůj skript podělit s jinými. Přímo v skriptu je totiž uvedeno, jaký shell se má použít pro jeho interpretování. Pokud byste chtěli místo Bournova shellu napsat skript pro ksh nebo bash, pak jej uvedete v prvním řádku a tím do jisté míry zajistíte, aby se ostatním lidem skript spustil správně. Samozřejmě, jen do jisté míry, protože existence prvního řádku nikomu nebrání, aby se pokusil skript spustit jedním z předchozích způsobů pomocí jiného interpretu.
Jako poznámku uveďme, že využití prvního řádku opravdu není omezeno na shellové skripty. Každý un*xový interpret, jehož vstupem jsou skripty v prostém textu, využívá podobného prvního řádku. Najdete je i v skriptech napsaných v Perlu, v Pythonu nebo v Ruby.
Něco málo o Unixu a multitasking
editovatProč mluvíme o multitaskingu
editovatPřestože tématem této knížky není Unix jako takový, některé aspekty Unixu musíme probrat víc do hloubky, abyste pochopili, proč Bourne shell funguje tak, jak funguje.
Jednou z nejdůležitějších vlastností un*xových operačních systémů, ve skutečnosti jednou z hlavních, kterými se v minulosti lišily od ostatních nejběžnějších operačních systémů (jako byl Microsoft DOS a z něj vycházející Windows, nebo MacOS), byla plná podpora více úloh a více uživatelů. Unixy byly od počátku navržené jako operační systémy pro počítače, které bude zároveň používat mnoho uživatelů, přičemž každý z nich bude chtít spustit svou vlastní úlohu; pravděpodobněji dokonce řadu svých úloh. Schopnost operačního systému efektivně rozdělit systémové zdroje, zejména procesorový čas, mezi mnoho úloh, které běží zdánlivě současně, se nazývá multitasking. Podpora multitaskingu obsažená už v základním návrhu operačního systému se promítla do leckterých jeho vlastností a ovlivnila i způsob, kterých se chovají shellová sezení.
Kdykoliv spustíte nový proces (například spuštěním programu), operační systém vytvoří pro tento proces vlastní běhové prostředí. To zahrnuje vlastní oblast paměti, kde se proces může realizovat, ale také to může zahrnovat předání nějakých přednastavení.
Když spustíte z běžícího procesu nový proces (například předáním příkazu shellovému programu v interaktivním režimu), pak se nový proces stává takzvaně potomkem dříve běžícího procesu (tedy program ls například běží jako potomek shellu). To je pro nás důležité proto, protože potomek dědí od svého předka kopii jeho prostředí. To znamená dvě věci:
- Protože potomek zdědí pouze kopii, nikdy nemůže měnit nastavení běhového prostředí svého předka, přístup má jen ke své kopii
- Pokud opravdu chcete provést nějakou změnu v prostředí svého shellu, nebo se naopak chcete takové změně vyhnout, potřebujete vědět, který příkaz je interpretován již puštěným shellem a který je spouštěn coby potomek. Jinak by se totiž mohlo stát, že se změní něco, co jste změnit nechtěli, nebo nezmění něco, co jste změnit chtěli
Shrnutí spouštění
editovatZpůsob spuštění | Běží jako |
---|---|
odeslání příkazu v interaktivním režimu |
|
předání shelu v neinteraktivním režimu | nový shell coby potomek současného |
puštění pomocí tečky(. MyScript) | součást současného shellu, má stejné běhové prostředí |
pomocí příznaku spustitelnosti a určení interpreta prvním řádkem | potomek s vlastním prostředím |
Užitečná znalost: procesy na pozadí
editovatZ dosavadního vyprávění o multiprocesingu by se mohlo zdát, že je to především komplikace pro psaní shellových skriptů. Kdyby to tak bylo, tak bychom žádný multiprocesing neměli. V Unixu není zvykem nechávat si neužitečné věci. Multiprocesing je neocenitelná možnost a lze jej použít i přímo v shellu. K tomu, abychom mohli dělat něco i ve chvíli, kdy spustíme nějaký dlouhotrvající proces. Abychom si zachovali přístup k shellu i během běhu dlouhého procesu, spustíme jej na pozadí.
Spustit proces na pozadí znamená sdělit při spouštění, že sice chceme spustit proces, ale nechceme, aby převzal plnou kontrolu nad vstupem a výstupem, které používá jeho předek, tedy abychom mohli dál používat klávesnici i obrazovku pro jinou práci. Stejně tak tím zároveň operačnímu systému přikážeme, aby nečekal s návratem kontroly rodičovskému procesu na ukončení procesu potomka, ale by kontrolu rodičovskému procesu vrátil obratem. Může to znít komplikovaně, ale nesmíte zapomenout, že tato schopnost je v Unixu odjakživa a Bournův shell byl zamýšlen jako pohodlné rozhraní pro ovládání celého systému. Proto také Bournův shell umí jednoduchým způsobem spustit nový proces na pozadí. Následující ukázka nám ukáže, jak na to, a zároveň nám ukáže, jak to může být užitečné. Zadejte na příkazový řádek následující příkaz (v podstatě nesmyslný, ale náročný na zdroje):
N=0 && while [ $N -lt 10000 ]; do date >> scriptout; N=`expr $N + 1`; done
Později pochopíme, jak takové složené příkazy fungují, ale v tuto chvíli nám stačí vědět, že tento příkaz si 10000× vyžádá od systému informaci o aktuálním datu a čase a vždy ji hned zapíše na konec souboru scriptout. Než to udělá 10000×, bude to chvilku trvat.
Teď to zkuste spustit s malou obměnou (totiž ampersandem na konci):
N=0 && while [ $N -lt 10000 ]; do date >> scriptout; N=`expr $N + 1`; done &
Rozdíl bude v tom, že se vám hned po spuštění opět zobrazí shellový prompt, protože úloha náročná na zdroje byla puštěna na pozadí.
Takže teď už to umíte: Proces na pozadí se v Bournově shellu spustí tak, že na konec příkazu napíšete znak &.
Poznámky
editovat- ↑ Ve skutečnosti se ovšem i v takovém případě dá vynutit spuštění zvláštního procesu. V pozdější kapitole si ukážeme, jak na to.
◄ Skriptování v Bournově shellu/Srovnání shellů | Spouštění příkazů | Skriptování v Bournově shellu/Prostředí ► |