První série dvacátého sedmého ročníku KSP
Celý leták, který posíláme také papírově, v PDF.
Zadání úloh
Tento rok jsme se rozhodli vám v každé sérii přinášet nějaký zajímavý příběh
točící se okolo určité zajímavé programátorské chyby. Takové chyby dělá občas
každý z nás, leč přesto někdy přerostou v příběh hodný zapamatování.
V jednotlivých dílech příběhu se budeme pokoušet
držet skutečných událostí, ale dovolíme si i jistou uměleckou licenci.
V prvním dílu se můžete začíst do příběhu, u kterého se nám nepodařilo zjistit,
kde se přesně odehrál. Některé zdroje vsazují události tohoto příběhu do
vojenského cvičení u Mrtvého moře a některé do Války v Zálivu (konflikt mezi
Irákem a koalicí západních zemí v čele s USA v roce 1991), my jsme se rozhodli
držet se verze z Perského zálivu.
Náš příběh začíná na palubě letadlové lodě USS Dwight D. Eisenhower
přezdívané posádkou familiárně Ike…
* * *
Poručík Stromboli rázoval chodbou k briefingové místnosti perutě. Ike byla
dlouhá loď, na délku přes 300 metrů, a on dostal kajutu zrovna na opačném konci.
Vyhnul se probíhající četě námořních pěšáků a během hlášení palubního rozhlasu
o příletu zásobovacího letu se protáhl průchodem do briefingové místnosti.
Už od rána byla loď napjatá tím, kdy se konečně zapojí do probíhajících operací.
Včera v noci vedly některé lodě operačního svazu masivní raketový útok na irácká
radarová postavení a proslýchalo se, že dnes v noci se dostane řada i na ně.
A piloti už se nemohli dočkat, aspoň tak působil šum v místnosti, když Stromboli
vešel a pokusil se sednout si na nějaké volné místo. Každý chtěl vidět co
nejlépe na hlavní bojový plán, ale zároveň mezi piloty existoval určitý kodex,
kterého se drželi i při uvolňování místa k sezení.
27-1-1 Zasedací pořádek (8 bodů)
Piloti v briefingové místnosti si postupně sedají na volné židle. Zasedací
pořádek si můžeme představit tak, že máme nekonečně dlouhou řadu židlí (židlí je
mnohem více, než dorazí pilotů) a každý nový pilot se nejdříve pokusí posadit na
prostřední židli.
Pokud je židle, na kterou si chce pilot sednout, volná, je vše v pořádku, pilot
se posadí a čeká na briefing. Pokud je však židle již obsazená jiným pilotem,
tak, než aby se hádali, sedne si jeden z pilotů na židli o jedno místo vlevo
a druhý na židli o jedno místo vpravo (původní židli tak nechají volnou).
Pokud by se při tomto rozsazování náhodou situace opakovala (pilot by se opět
chtěl posadit na židli, kde už někdo sedí), bude se postup opakovat tak dlouho,
dokud na každé židli nebude sedět maximálně jeden pilot.
Chceme po vás dvě věci:
- Jak bude řada židlí vypadat po příchodu N pilotů?
- Dostanete zapsaný nějaký zasedací pořádek pilotů (obsazené a neobsazené
židle). Rozhodněte, zdali mohl vzniknout tímto postupem.
Řešení
Konečně se všichni posadili, do místnosti vešel velitel a začal briefing. Vypadá
to dobře, dneska se konečně odlepí od letové paluby, zasnil se Stromboli, a tak
si skoro nevšiml na něj mířené otázky.
„Tak Stromboli, přestaňte lelkovat a poslouchejte!“ napomenul ho velitel,
„Říkal jsem, že dneska odpoledne provedete s Thompsonem průzkumný let v nízké
výšce. Přesné pokyny a letový plán obdržíte během několika hodin, zatím se
připravte. Technici vám zrovna na vašeho ptáčka montují průzkumnou výbavu.“
„Ano pane!“ odpověděl spěšně Stromboli a s úsměvem mrknul na svého navigátora
Thompsona.
Schůze ještě chvíli pokračovala, než se rozdaly úkoly pro všechny piloty, a pak
Stromboli v závěsu se svým navigátorem vyrazil směrem k hangárové palubě. Chtěl
si ještě před akcí promluvit s vrchním zbrojmistrem a vybrat si vybavení.
Ve chvíli, kdy dorazil do zbrojnice, trochu se zděsil. Z vedlejšího zbrojního
skladu se totiž ozýval děsivý lomoz, a tak tam opatrně nakoukl – vrchní
zbrojmistr stál uprostřed místnosti a dirigoval sundavání palet se zbraněmi
z vysokých polic.
27-1-2 Zbrojní sklad (9 bodů)
Vrchní zbrojmistr na letadlové lodi potřebuje vyndat ze skladu několik
palet s výzbrojí. Sklad je ale zaskládaný do veliké výšky a manévrování
s neohrabanými vysokozdvižnými vozíky je v něm celkem nebezpečné, aspoň do doby,
než se část věcí vyndá.
Ve skladu operují dva různé vysokozdvižné vozíky (určené pro palety dvou
velikostí) a bezpečností předpisy dovolují na začátku sundavat pouze palety
uložené na policích v maximální výšce h0. Na vstupu dostanete popis všech
N palet ve skladu, paleta i je velikosti vi (velká nebo malá), je uložena ve
výšce hi a má nebezpečnost xi.
Vozíky se musí v sundavání palet střídat (velká paleta, malá paleta, velká
paleta, …) a po vyndání palety s nebezpečností xi mohou oba vozíky začít
sundavat palety z výšky o xi větší než dosud.
Hlavního zbrojmistra by zajímalo, kolik palet může ze skladu vyvézt ven, aniž
by porušil bezpečností předpisy.
Řešení
Konečně byla Stromboliho stíhačka připravená a vyzbrojená k průzkumné misi.
Zašel si tedy na velmi pozdní oběd a pak se opět vydal do hangáru ke svému
stroji. Usedl do kokpitu a pustil se do předletové přípravy. Po jejím dokončení
pak ukázal palubnímu mechanikovi zdvižený palec a nechal se vyvézt výtahem na
letovou palubu, kde počkal, než na něj dojde řada se startem.
Konečně, rameno katapultu se zakleslo za přední podvozkovou nohu
„ef čtrnáctky“, Stromboli ukázal technikovi zdvižený palec, přidal tah motorů
a pak už se jejich F14 Tomcat vyřítil po krátké vzletové dráze vstříc slunci.
Rychle vystoupali do výšky několika kilometrů a tam začali kroužit. Museli
počkat, než dostanou od velitelství povolení k provedení akce. Thompson na
zadním sedadle mezitím zapnul nový navigační systém, počkal, než se přijímač GPS
ustálí, a začal prověřovat jeho funkčnost a propojení s průzkumným kontejnerem
s kamerami, který měli zavěšený pod pravým křídlem.
Stromboli nechal Thompsona hrát si, navedl letadlo na kruhovou vyčkávací dráhu
a čekal na finální pokyn k zahájení akce. Vzdušný prostor aktuálně brázdilo
mnoho spojeneckých letounů – hlídky, zásobovací stroje i další průzkumné mise
– a tak bylo potřeba udržovat přesně vymezené letecké koridory, aby se nikdo
s nikým nesrazil. Naštěstí měla jejich mise nejvyšší prioritu.
27-1-3 Letecké koridory (10 bodů)
Vzdušný prostor nad spojeneckým námořním svazem není vůbec prázdný, a tak všechny
letouny, které se v něm pohybují, musí dodržovat předepsané letové trasy neboli
koridory.
Koridory mají předepsaný směr, kterým se jimi dá proletět, a vedou mezi určenými
místy vzdušného prostoru (koridory a místa tak tvoří hrany a vrcholy
orientovaného grafu).
Letoun se potřebuje dostat od letadlové lodi k místu plnění své mise, tedy je
potřeba nalézt orientovanou cestu mezi dvěma zadanými místy.
Pilot letounu chce letět nejkratší trasou a zajímá ho, kolik má možností volby,
tedy kolik různých nejkratších orientovaných cest vedoucích mezi těmito dvěma
místy existuje (různé cesty jsou takové, které se liší alespoň v jedné hraně).
Řešení
Už začal přicházet soumrak, když konečně dostali očekávané rozkazy. Stromboli
vysílačkou potvrdil příjem, uchopil knipl a začal s Tomcatem klesat. Když se
přiblížili k pobřeží a sestoupili do několika desítek metrů nad vodu, snížil
rychlost a změnil šípovitost křídel na pomalý let. Nastavitelná křídla, to byl
důvod, proč tyhle starší stroje pořád miloval.
Letoun sestoupil ještě o kus níž, už letěli jen pár metrů nad vlnami. Pod nimi
se mihla pláž, Stromboli navedl Tomcat do jedné prolákliny a vtom se to stalo!
Najednou za táhlého pískání zablikaly a zhasly všechny displeje v kokpitu
a stroj se hrozivě otřásl, jak se začal naklánět na bok. Stromboli hned popadl
knipl a přitáhl ho, šlo to mnohem hůř než obvykle. „Co se stalo, zasáhlo nás
něco?“ křikl dozadu na Thompsona. „Nevím. Já…najednou všechno zhaslo,
asi porucha.“
Stromboli zaklel, zatracená elektronika, pomyslel si. Jeho pohled zabloudil
k panelu vysílačky u levého kolena, ta ještě jako jedna z mála svítila, nebyla
připojená k modernizovanému palubnímu počítači. „Mayday, mayday. Tady Krysa
jedna, volám základnu. Mayday, mayday. Těžká porucha palubní elektroniky, stroj
stěží ovladatelný, vracíme se na základnu.“
Ještě že v zapadajícím slunci byla jasně vidět černá tečka letadlové lodi.
Stromboli k ní zamířil a doufal, že to stroj zpět na loď zvládne, bez
asistence palubní elektroniky totiž vůbec nevěděl, jaký je jeho stav. Thompson
se mezitím vzadu pokoušel zprovoznit alespoň průhledový Head-up display, aby
Stromboli při přiblížení viděl před sebou jejich rychlost.
27-1-4 Head-up display (10 bodů)
Head-up display (HUD) zobrazuje informace v zorném poli pilota, a ten tak nemusí
sklánět oči dolů a pak se jimi zase vracet. Bohužel je však docela citlivý na
vyladění barev a kontrastu, a pokud se nastaví nesprávně, spíš pilota ruší.
HUD má N různých prvků. Každému z nich můžeme nastavit kontrast na nějakou
hodnotu mezi 0 a K včetně. Prvky jsou na HUDu uspořádány vedle sebe, takže
si je můžeme představit jako řadu N čísel.
Když poprvé spustíme HUD, dostaneme nějak nastavený kontrast. Chceme přenastavit
kontrast všech prvků tak, aby se žádné dva prvky vedle sebe nelišily o více než
D jednotek, a zároveň chceme provést co nejmenší celkovou změnu kontrastu
(součet změn bude nejmenší možný).
Formát vstupu: Na prvním řádku budou čísla N, K a D, na druhém řádku
pak N čísel udávajících výchozí kontrast všech prvků. Čísla jsou na řádku
oddělena mezerou.
Formát výstupu: Na první řádek vypište součet provedených změn, na druhý
pak uveďte nové hodnoty kontrastu pro všechny prvky (tedy N čísel oddělených
mezerou). Pokud existuje více optimálních řešení, vyberte si libovolné z nich.
Ukázkový vstup:
6 30 3
2 7 9 13 16 14
Ukázkový výstup:
3
4 7 10 13 16 14
Toto je praktická open-data úloha. V odevzdávátku
si necháte vygenerovat vstupy a odevzdáte příslušné výstupy. Záleží jen na vás, jak výstupy vyrobíte.
Řešení
Stromboli navedl Tomcat na přistání a vysunul brzdící hák. Tohle přiblížení bez
přístrojů nechtěl opakovat a byl rád, že slunce ještě nestihlo zapadnout. Už mu
však moc nescházelo, a tak Stromboli s pozorností vybičovanou na maximum zahájil
závěrečnou fázi přistávacího manévru.
Zadní kola dosedla na přistávací dráhu. Hák sice minul první brzdící lano, ale
o druhé se již pevně zasekl a Tomcat, brzděný pružným lanem, zpomalil na
několika metrech dráhy na nulu. Stromboli si vydechl, vypnul oba motory, sundal
si helmu a prohrábl si zpocené vlasy. Tohle zvládli, teď bylo potřeba přijít na
to, co se stalo.
Ještě ten večer si technici vzali jejich Tomcat do parády. Začali k němu
připojovat všemožné diagnostické přístroje a zkoumali jejich údaje. Připojení
diagnostických přístrojů k nefunkční elektronice ale není tak jednoduché, každý
přístroj má totiž mírně odlišné požadavky na napájení.
27-1-5 Napájení přístrojů (10 bodů)
Technici připojují diagnostické přístroje k rozbité elektronice. Každý kus
elektroniky má nějaký svůj povolený rozsah napájení (minimální a maximální
hodnotu napětí, při které bezpečně funguje).
Technici mají k dispozici laboratorní zdroje, které je možné nastavit na přesné
napětí. Každý laboratorní zdroj může napájet neomezeně mnoho kusů elektroniky.
Protože jsou ale laboratorní zdroje hodně používaná věc a na technické palubě
letadlové lodě je o ně velký zájem, chtějí jich technici použít co možná nejméně
(aby jich co nejvíce zbylo na ostatní práce). Pomozte jim zjistit nejmenší možný
počet zdrojů, se kterými ještě dokážou uspokojit požadavky napájení všech kusů
elektroniky dohromady.
Tato úloha je praktická a řeší se ve vyhodnocovacím systému
CodEx.
Přesný formát vstupu a výstupu, povolené jazyky a další technické informace
jsou uvedeny v CodExu přímo u úlohy.
Řešení
Technici pracovali celou noc, ale na žádnou závadu na hardware nepřišli. Pro
jistotu vyměnili jednotku palubního počítače a navigační systém. Další den
večer se průzkumný let měl opakovat a rozkaz dostali opět Stromboli s Thompsonem.
Tentokrát se vznesli už za tmy a rovnou zamířili k oblasti, kterou měli v nízké
výšce prolétnout. Stromboli opět klesl s letounem při nízké rychlosti do kaňonu
a začali snímkovat kaňonem vedoucí silnici.
Pak Stromboli přitáhl Tomcat do těsného stoupání na konci kaňonu. Teď půjde do
tuhého, pomyslel si, a navedl letoun nad hlavní cíl jejich průzkumu, těsný
průlet nad iráckým letištěm. Díky letu v nízké výšce o nich do poslední
chvíle nevěděli, a tak se protiletecká palba začala objevovat až s dlouhým
zpožděním.
První zareagovala nějaká hlídka. Spustila palbu z ručních zbraní, se
kterými ale neměli skoro žádnou šanci Tomcat zasáhnout. První protiletadlový
kanón vystřelil až ve chvíli, kdy dokončili oblet letiště a začali se stáčet
směrem zpět k základně.
Stromboli spustil přídavné spalování a za bojového pokřikování navedl letoun do
táhlé zatáčky, která je dostala mimo dosah protiletecké palby. Rád by udržoval
přídavné spalování déle a vychutnával si ten příval adrenalinu, když ho silné
přetížení tlačilo do sedačky, ale pohled na ukazatel paliva mu to rozmluvil.
Stáhl výkon zpět do normálních hodnot a začal svým letem kopírovat zemi,
aby se držel mimo dosah posledních fungujících iráckých radarů. Když v tom se to
stalo znovu…
Tomcat právě klesal do nějaké prohlubně, když zhasly všechny displeje v kabině
a přestal fungovat radar, kterým se Stromboli řídil při nízkém letu nad zemí.
Instinktivně přitáhl letoun o kus výš, aby se vyhnul překážkám, které teď
neviděl, a opět zahlásil do vysílačky celkové selhání palubní elektroniky.
Teď byla ale situace vážnější, byla noc a návrat na základnu byl o to těžší.
Z letecké patroly v blízkosti byla odvelena jedna F15, která je rychle dohnala
a s rozsvícenými pozičními světly se usadila půl kilometru před nimi. Takhle je
jako pasáček ztracenou ovci dovedla až nazpět k Ike, kde mezitím palubní
personál řešil další problém s navigačními světly.
27-1-6 Přistávací světla (12 bodů)
Navigační světla na palubě letadlové lodě jsou tvořena třemi barvami: červenou,
zelenou a modrou. Jsou rozmístěna podél dráhy v řadě N světel.
Palubní důstojník chce rozsvítit nějaký úsek světel tak, aby při pohledu skrz
všechna svítící světla působil bíle. A zároveň chce, aby světlo bylo co
nejsilnější, tedy aby svítilo co možná nejvíce světel.
Potřebuje tedy najít nejdelší souvislý úsek, ve kterém jsou všechny tři barvy
zastoupeny ve stejném počtu.
Lehčí varianta (za 8 bodů):
Vyřešte stejnou úlohu, ale jen pro dvě různé barvy.
Řešení
Díky dobře osvětlené přistávací dráze a skvělému pilotnímu umu se Strombolimu
povedlo i podruhé usadit letoun do brzdících lan bez jakékoliv navigační pomoci.
Teď už byl však rozhněvaný, dvakrát stejná závada se mu vůbec nelíbila.
Během převozu letadla výtahem na hangárovou palubu tedy prohodil několik
nevybíravých vět s vrchním mechanikem a po ohlášení u velitele a krátkém hlášení
padl vyčerpaný do postele. Alespoň že snímky tentokrát dovezli, a mise tak byla
hotová.
* * *
Technici mezitím znovu prolezli celou F14 a hledali závadu v hardware. Nikde
však žádnou nenašli, a tak obrátili svůj pohled k softwaru. A zde je čekalo velké
překvapení, jedno drobné přehlédnutí, které způsobilo pád celého palubního
počítače.
Letoun byl totiž vybaven novou verzí systému GPS, která mimo jiné počítá podle
signálu z družic i nadmořskou výšku. Ukázalo se však, že se v jednom místě
nadmořskou výškou dělí, aniž by byla zkontrolována nenulovost této
hodnoty. A jelikož poručík Stromboli navedl letoun při obou letech do nízkého
průletu kaňonem, jehož nejnižší bod se nacházel pod úrovní referenční mořské hladiny
používané v GPS, došlo v obou případech k dělení nulou.
To pak vlivem propojení přístrojů v F14 zapříčinilo pád zbytku elektroniky
(řízení ale ovlivněno nebylo, to je v F14 přenášeno ještě hydraulicky
a mechanicky). Technici se z tohoto problému snad poučili a aktualizovali
software zbytku amerických letadel – alespoň od té doby žádné podobné příběhy
nejsou. Nebo vlastně… ale o tom zase třeba příště.
Jirka Setnička
27-1-7 Učíme se s UNIXem (14 bodů)
V letošním seriálu jsme se rozhodli trochu vás seznámit s UNIXovými systémy,
přesněji hlavně s tím, jak efektivně (a efektně) používat jejich příkazovou řádku.
Naučíme vás, že UNIXová příkazová řádka je kamarád, kterého se nemusíte bát –
neoplývá sice (většinou) klikacím barevným rozhraním, kterým vás provede virtuální
pomocník v podobě pana Sponky (personifikovaná nápověda v jednom
nejmenovaném kancelářském balíku), ale o to je mocnější.
Seriál bude směřován hlavně praktickým způsobem a jednotlivé úkoly by vás měly
naučit UNIX skutečně používat. Nejprve se ale nevyhneme malému historickému
úvodu o vývoji UNIXu a různých shellů, hlavně bashe.
UNIX, POSIX, shell, bash, … Co to všechno je?
Historie UNIXu se začala psát v roce 1969, kdy v Bellových laboratořích vznikl
tak trochu potají nový operační systém (vedení firmy v nově vyvíjeném operačním
systému tehdy nevidělo velkou budoucnost, a tak ho jeho vývojáři před vedením
vydávali za textový editor, aby na vývoj získali čas a zdroje). Teprve
začátkem 70. let dostal systém oficiální podporu a začal se překotně vyvíjet.
UNIX je ale v současnosti registrovaná ochranná známka a mohou ji využívat
pouze systémy, které splňují určené podmínky a k tomu platí licenční poplatky
(navíc licenci získává vždy jen určitá verze systému, a licencování je tak pro
rychle se vyvíjející systémy finančně i časově neúnosné).
Z tohoto důvodu vzniklo několik systémů, které jsou od UNIXu pouze odvozené.
Všechny ale splňují společný standard zvaný POSIX,
který zaručuje vzájemnou kompatibilitu, a obecně se o nich mluví jako o UNIXových
systémech. Nejrozšířenějším z nich je Linux, který sám existuje
v záplavě různých variant (tzv. distribucí). Dalším známým systémem je například BSD vyvíjený
na Kalifornské univerzitě v Berkeley.
Všechny tyto systémy ale spojuje příkazová řádka, ve světě UNIXu se jí říká
shell a běží v terminálu. Terminál je přímo věc, která se stará
o čtení vstupu z klávesnice a zobrazení výstupu na monitor, ale nemá
žádnou vnitřní logiku, o tu se stará shell (který se zase nemusí zajímat
o klávesnici a monitor, ale má už jen svůj standardní vstup a výstup).
Shell je jednoduše řečeno textové rozhraní, které umožňuje spouštět příkazy
a pomocí nich ovládat celý systém. Je to takový předchůdce grafických
rozhraní a existují stroje (například některé servery), kde grafické rozhraní
vůbec není nainstalováno a celé ovládání se děje právě jen přes shell.
Ale i shell sám existuje v několika různých variantách, i on se postupně vyvíjel
a byl obohacován o nové vlastnosti a příkazy. Shell, se kterým se dneska setkáme
skoro na všech linuxových strojích, se nazývá bash (zkratka za Bourne
again shell, což je odkaz na starší Bourne shell). V něm se budeme
pohybovat většinu času, ale pokusíme se zdůrazňovat, které příkazy jsou
univerzální a budou fungovat ve všech POSIXových shellech, a které jsou jen
specialitou bashe.
Jak si bash pořídit?
Pokud máte Linux, skoro určitě máte bash nainstalovaný. Stačí ve vašem systému
pouze spustit Terminál (či nějak podobně nazvanou aplikaci) a objeví se vám
(většinou černé) okno, kam je možné psát příkazy a prohlížet si jejich výsledky.
Je ale možné, že na svém stroji nebudete mít nastavený bash jako výchozí
a spustí se vám nějaký jiný, jednodušší, shell. V takovém případě v něm
jen spusťte příkaz exec bash
a jste v bashi.
Ve Windows je situace o trochu složitější, ale i zde si můžete UNIXový bash
pořídit (organizátoři KSP ho při práci ve Windows doporučují jako věc, která vám
usnadní život). Nejlepším řešením bude instalace programu Cygwin, který
vám nainstaluje bash a spoustu šikovných utilit. Jeho instalaci máme popsanou
v naší Encyklopedii.
První kroky po systému
Než vůbec uděláme první krok, měli bychom si v rychlosti představit UNIXový
souborový systém. Jeho hlavní myšlenkou je, že vše je uspořádáno ve stromu, do
kterého se na různá místa zapojují správné věci, třeba různé disky. Kořen
souborového systému se označuje jako adresář /
(lomítko), domovským
adresářem uživatele hroch
pak adresář /home/hroch
. Je klidně možné,
že celý adresář /home
sídlí fyzicky na jiném disku (třeba i síťovém),
který se do stromu souborů připojil na správné místo.
Názvy souborů i adresářů mohou tvořit libovolné znaky (mezery, písmena
s diakritikou, …) s jedinou výjimkou, a tou je lomítko, to se totiž používá
pro oddělování názvů adresářů v cestě. Nedoporučujeme ale vytváření názvů
obsahujících různé speciální znaky jako []"?*
a podobně (může se dokonce
stát, že některé programy a systémy budou – pro vaši ochranu – vytváření
takových souborů blokovat).
V názvech také záleží (na rozdíl od operačních systémů Windows) na velikosti
písmen, fotka.jpg
a fotka.JPG
jsou rozdílné soubory.
Když poprvé spustíme bash, uvidíme podobný řádek:
hroch@ksp:~$
Ten nám říká náš login (jméno, pod kterým jsme se přihlásili), stroj, na kterém
náš bash běží, a také nám prozrazuje jméno adresáře, ve kterém se aktuálně
nacházíme. Za znakem $
pak můžeme psát příkazy. Ale počkat, co je vlnka
za adresář a kde je připojený ve stromu souborů? Není to nic tajuplného, je to
jen zkratka za náš domovský adresář, tedy za /home/hroch
, aby ve výpisu
nezabíral tolik místa.
Začneme se shellovým Hello World: Napište příkaz echo Hello World
a spusťte ho klávesou Enter. Příkaz echo
(anglicky „ozvěna“) udělá to,
že opíše všechny své parametry na svůj výstup.
Většina příkazů v shellu totiž může být ovlivněna zadanými parametry, některé
příkazy bez zadaných parametrů dokonce ani nefungují. Parametry jsou od sebe
a od příkazu v shellu odděleny mezerami a rozlišujeme dva základní typy
parametrů – přepínače a poziční argumenty. K jejich pořádnému vysvětlení se
dostaneme za chvíli, zatím si pojďme ještě chvíli hrát.
Chcete nějaký zajímavější příkaz než echo
? Zkuste si spustit příkaz
pwd
. Tento příkaz vypíše cestu do aktuálního adresáře (je to zkratka za
„print working directory“). Jak se ale přepnout do nějakého jiného? K tomu
slouží příkaz na změnu adresáře cd
(„change directory“), tomu do
parametru můžeme napsat, kam nás má přepnout (bez parametru nás přepne do našeho
domovského adresáře).
Zkuste si třeba cd /
nebo cd /home
. Cestám zapsaným s lomítkem
na začátku říkáme absolutní a udávají přesné místo v adresářovém stromě,
kam se přesunout. Druhou možností je použít cestu
relativní vzhledem k pracovnímu adresáři, ta se píše bez úvodního
lomítka. Například spuštění cd hroch
v adresáři /home
nás přesune
do /home/hroch
. Můžeme si to představit tak, že před takovouto cestu
se automaticky připojí výstup příkazu pwd
a lomítko.
Speciálním „podadresářem“, který se vyskytuje všude, je adresář ..
(dvě
tečky). To je odkaz ukazující o úroveň výš, když tedy ve svém domovském adresáři
spustíme cd ..
, přepne nás to do adresáře /home
. Dalším speciálním
adresářem je adresář .
(tečka), která odkazuje na aktuální adresář – to
vám teď může připadat matoucí a nadbytečné, ale v dalších dílech ukážeme, na co
se tento odkaz používá.
Poslední, co k pohybu po systému potřebujeme, je příkaz, který by nám vypsal
obsah aktuálního adresáře. To je příkaz ls
(od anglického slovesa
„list“). V základní verzi nám vypíše všechny adresáře a soubory v aktuálním
adresáři kromě skrytých (začínajících tečkou), později se s ním naučíme některé další šikovné věci.
Pokud si budete chtít nějaký ze zmíněných příkazů více prostudovat, můžete
použít manuálové stránky. Pro zobrazení manuálových stránek k příkazu
abc
zadejte v bashi příkaz man abc
, a pokud k příkazu abc
tato
stránka existuje, zobrazí se vám (k příkazům cd
a pwd
ale
v některých systémech manuálové stránky neexistují, jelikož se jedná o interní
příkazy shellu a ne o samostatné programy).
V manuálové stránce je většinou uvedený základní popis příkazu, možné parametry
a občas i ukázkové použití. Pro ukončení prohlížení a návrat do shellu stiskněte
q
. Doporučujeme si zběžně pročíst manuálové stránky dále zmiňovaných
příkazů, mohou se vám hodit.
Vytváření a mazání adresářů a souborů
Již umíme procházet po adresářích, pojďme si také nějaké vytvořit a smazat:
- Vytvoření prázdného adresáře provedeme zavoláním příkazu
mkdir
název adresáře.
- Smazání adresáře (musí být prázdný) uděláme pomocí
příkazu
rmdir
název adresáře,
nesmíme se v tu chvíli ale nacházet uvnitř tohoto adresáře.
- Vytvoření prázdného souboru můžeme provést pomocí příkazu
touch
název souboru. Pokud takový soubor neexistuje,
příkaz ho vytvoří; pokud existuje, nastaví mu datum modifikace na aktuální okamžik.
- Smazání souboru zařídíme zavoláním
rm
název souboru.
Všechny názvy můžeme uvádět i jako cesty, zavolání touch adresar/soubor
vytvoří soubor
v adresar
, pokud adresar
již existuje (jinak
skončí zavolání chybou). Pokud chceme najednou spustit více příkazů, dá se to
provést jejich zápisem na jednu řádku a oddělením pomocí středníku.
Úkol 1 [2b]
Vytvořte prázdný soubor test
umístěný v nově vytvořeném podadresáři
~/a/b/c/d
(vlnka tu, jak je zvykem, zastupuje váš domovský adresář). Pak
zase adresáře i soubor vymažte. Zkuste použít co možná nejméně příkazů.
U všech úloh odevzdávejte posloupnost příkazů vedoucích ke splnění dané úlohy
(pokud nebude uvedeno jinak).
Ještě doplníme další tři příkazy, které souvisejí s prací se soubory:
- Příkaz
cp
(zkratka za copy) slouží ke zkopírování (klidně více)
souborů do zadaného umístění. Původní soubory zůstanou na místě a v cílovém
umístění se vytvoří jejich kopie.
- Příkaz
mv
(zkratka za move) dělá podobnou věc jako cp
, jen
soubory nekopíruje, ale přesouvá (a umí přesouvat i adresáře). Stojí za
poznámku, že pokud je původní i cílové umístění na stejném fyzickém disku, je
mv
řádově rychlejší, než kombinace cp
a rm
– jen se totiž
upraví záznam v tabulce souborů a data se fyzicky nemusejí nikam přesouvat
(dalo by se říci, že vlastně dojde jen k přejmenování a přepsání adresy).
- Příkaz
cat
(zkratka concatenate) vypisuje obsah zadaných souborů
na terminál. Hodí se jednak pro prohlížení obsahu krátkých souborů, jednak pro
svůj původní účel (konkatenaci – zřetězení). Když zadáme více názvů souborů, cat
je
všechny spojí a vypíše na terminál (později se dozvíme, jak výstup na terminál
přesměrovat někam, kde se nám hodí víc).
Příkazy cp
a mv
přebírají libovolně mnoho parametrů: vezmou všechny
parametry až na poslední jako zdrojové soubory a zkopírují/přesunou je do místa,
kam odkazuje poslední parametr. Teď by stálo za to pořádně si rozebrat, co
všechno může být obsaženo v parametrech a jaké triky s nimi umíme.
Parametry: Přepínače a poziční argumenty
Přepínače jsou, jak již název napovídá, parametry, které upravují
nějakým způsobem běh příkazu. Jsou uvozeny jednou nebo dvěma pomlčkami (je
zvykem, že jednou pomlčkou jsou uvozeny jednopísmenné a dvěma pomlčkami
vícepísmenné, ale neplatí to vždy).
Například nám již známý příkaz ls
má přepínač -l
zapínající dlouhý
výstup. Když si tedy spustíme příkaz ls -l
, vypadne na vás pravděpodobně
výpis podobný tomuto:
drwxr-xr-x hroch ksp 4096 čen 16 12:00 adresar
-rw-r--r-- hroch ksp 0 čen 16 12:00 soubor
Zde se dozvíme (popořadě) přístupová práva k souboru, jeho vlastníka a skupinu
(těmito věcmi se budeme zabývat v některém z příštích dílů), velikost, datum
poslední změny a na úplném konci nalezneme název.
Při zápisu více přepínačů je můžeme psát buď všechny samostatně
(prikaz -a -b -c
), nebo můžeme jednopísmenné i sdružit dohromady
(prikaz -abc
), fungovat budou stejně. Pokud nějaký přepínač bude přijímat
doprovodný parametr (většinou to je číslo), může zápis vypadat třeba takto:
prikaz -ab 3 -c
(tady přepínač b
přijal parametr 3), nebo dokonce
prikaz -acb3
.
Pořadí přepínačů je u většiny základních příkazů libovolné (když nebude,
upozorníme vás), ale u některých programů, které nejsou napsané tak pečlivě
jako základní shellové příkazy, na jejich pořadí záležet už může. V takovém
případě doporučujeme pročíst manuál od daného programu.
Druhý typ parametrů nazýváme poziční argumenty. Ty se
zadávají bez nějakých uvozujících pomlček a tradičně až za všemi přepínači.
Často to jsou například názvy souborů a adresářů (viz příkazy cp
a mv
).
Zvídavější z vás možná ve spojitosti s výše jmenovanými příkazy napadla jedna
otázka: „Jak zkopírovat/smazat soubor s mezerou v názvu?“ Na to se dá jít
dvěma způsoby:
- Speciální znaky (mezi něž patří i mezera) můžeme escapovat, tedy zbavit
je jejich speciálního účinku, předřazením zpětného lomítka. Napsáním
rm deravy\ nazev
tedy předáme příkazu rm
jediný parametr – název
souboru obsahujícího mezeru.
- Druhou možností je použití uvozovek, příkaz výše bychom mohli přepsat na
rm "deravy nazev"
se stejným účinkem. Použít se dá i zápis
s jednoduchými uvozovkami (apostrofy) a v tomto případě by byly ekvivalentní,
rozdíl je však v tom, že ve dvojitých se expandují proměnné, kdežto
v jednoduchých ne (více o proměnných v příštích dílech).
Poslední důležitou věcí ohledně parametrů je, jak oddělit přepínače od
pozičních argumentů. Představme si například, že bychom chtěli smazat soubor,
který by se jmenoval „-f
“. Nemůžeme napsat jenom rm -f
, protože to
se vyhodnotí jako přepínač, a ani rm "-f"
nám nepomůže, protože bash
stejně předá příkazu rm
jenom parametr -f
.
Řešením je oznámit příkazu místo, kde končí přepínače. To uděláme pomocí
osamocené dvojice pomlček. Za tímto místem se již nemohou nacházet žádné
přepínače a příkaz všechno zbylé vyhodnotí jako poziční argumenty. Řešení tedy
vypadá takto: rm – -f
.
Úkol 2 [2b]
Prostudujte si manuálové stránky příkazů head
a tail
, hlavně jejich
parametry, a zjistěte, jak vypsat prvních a posledních patnáct řádků souboru
a jak vypsat všechno až na prvních patnáct řádek. Vyzkoušejte si to třeba na
souboru /etc/passwd
.
Doplňování a wildcardy
Představme si, že se chceme přepnout do adresáře, jenž má hrozně dlouhý název.
Bash nám to dokáže usnadnit: Pokud totiž při psaní názvu zmáčkneme tabulátor,
pokusí se doplnit (podle již napsaného začátku) zbytek názvu souboru nebo
adresáře.
Pokud existuje několik souborů nebo adresářů, které mají stejný prefix jména,
doplní bash po stisku tabulátoru nejdelší společnou část a po dalším stisku
zobrazí jména, kterými se dá pokračovat. Pak stačí jen napsat další část názvu,
opět stisknout tabulátor a nechat si doplnit zbytek. Věřte, že to řádově urychlí
pohyb po adresářovém stromě a je to jedna z nejpoužívanějších kláves. :-)
Dalším dobrým trikem jsou šipky nahoru a dolů, které nám dovolí listovat
v historii příkazů a znovu je spouštět nebo upravovat.
Dobře, teď již umíme s bashem pracovat efektivněji, ale co když budeme chtít
zkopírovat stovky souborů (třeba fotek z výletu), to je musíme vážně všechny
vypisovat? Bash nám pomůže i v tomto případě, užitím zástupných značek neboli
wildcardů.
Wildcardy fungují jako žolíky, umožní nám nahradit část názvu souboru zástupným
znakem. Ve skutečnosti se stane to, že bash najde všechny soubory, které
odpovídají použitým zástupným znakům, a nahradí jimi výraz s wildcardy
v příkazu (říkáme, že se expanduje na tyto soubory). Samotný příkaz tedy
nevidí wildcardy, ale dostane od bashe rovnou seznam odpovídajících souborů.
Jedinou výjimkou je, když žádné takové soubory neexistují, v takovém případě
nechá bash výraz s wildcardy beze změny.
Mezi wildcardy patří:
- Otazník
?
zastupuje libovolný znak: mal?.txt
tedy odpovídají
například soubory mala.txt
, maly.txt
a male.txt
(naopak
mal.txt
neodpovídá).
- Hvězdička
*
zastupuje libovolný (i nulový) počet nějakých znaků:
fot*.jpg
odpovídají foto001.jpg
i fot.jpg
. Speciální výjimkou
jsou skryté soubory, na ty se wildcardy neexpandují (pokud
explicitně nenapíšeme tečku na začátku názvu).
- Hranaté závorky
[]
se používají pro výčet nebo rozsah: výrazu
[13579]
bude odpovídat libovolná lichá číslice, výrazu [0-9]
libovolná číslice z rozsahu 0 až 9 a výrazu [0-9A-F]
zase libovolná
šestnáctková číslice. Pokud jako první znak v závorce uvedeme stříšku, funguje
celá závorka jako negace (výrazu [^0-5]
odpovídá všechno až na číslice
0 až 5). Stejného efektu docílíme ve většině moderních shellů také vykřičníkem.
Další speciální konstrukcí shellu, která se často kombinuje s wildcardy,
jsou složené závorky {}
. Nejsou to wildcardy, takže se vůbec nedívají na
to, jestli nějaké jimi popisované soubory existují nebo ne, ale daly by se
přirovnat spíše k syntaktické zkratce.
Jejich zápis je tvořen několika výrazy oddělenými čárkami (ve spojení
s wildcardy například *.{jpg,mp[34]}
) a bash udělá to, že ještě před
zpracováním klasických wildcardů rozepíše výrazy obsahující složené závorky na
všechny jejich možné varianty – vytvoří samostatný výraz pro každou z variant
uvedených ve složené závorce (z příkladu výše tak vznikne dvojice
*.jpg *.mp[34]
, která se teprve zpracovává dál).
Pokud budeme pracovat v bashi (jiné shelly podobnou funkci obecně mít nemusí,
i když zase mohou obsahovat jiná vylepšení), můžeme ve složených závorkách
použít i rozsah. Zápis {1..20}
je ekvivalentní s vypsáním dvaceti čísel
oddělených čárkou ve složených závorkách.
Rozdíl oproti wildcardům se dá pozorovat třeba mezi příkazy mkdir adresar{5,6,7}
a mkdir adresar[567]
. První provede,
co bychom od něj očekávali (vzniknou tři nové adresáře), ale druhý pro
neexistenci daných adresářů vytvoří adresář s hranatými závorkami v názvu
(wildcardy se neexpandují).
Pro zkoušení wildcardů v nějakém adresáři můžete použít příkaz echo
, který
vám vypíše všechno, co dostane jako parametry – tedy všechny expandované názvy
souborů v aktuálním adresáři, nebo původní wildcard, pokud se expanze nepovedla.
Úkol 3 [1b]
Jak byste smazali soubor, který obsahuje v názvu nějaký wildcard? Například jak
byste smazali soubor a?c
a přitom nesmazali abc
, nebo smazali
adresar[567]
, ale již ne existující adresar5
?
Úkol 4 [3b]
Vymyslete co nejkratší zápis pomocí wildcardů, kterému budou odpovídat právě
všechny soubory s příponami jpg
, jpeg
nebo gif
v podadresářích
aktuálního adresáře; názvy podadresářů musí obsahovat buď alespoň dvě číslice
0 až 9 nebo alespoň dvě písmena anglické abecedy (pozor na velikost písmen).
Důkladně popište, co která část výrazu dělá. Můžete předpokládat, že od
každého typu bude alespoň jeden soubor a adresář existovat.
Roury a přesměrování vstupu a výstupu
Kromě parametrů pracují ještě shellové příkazy se vstupem a výstupem. Parametry
většinou slouží k nastavení chování příkazu, kdežto data, která chceme příkazem
zpracovat, patří na jeho vstup.
První metodou zadávání vstupu je přímo jeho psaní na terminál. Zkuste si spustit
například příkaz wc
(zkratka za word count). Ten slouží k počítání
slov, písmen a řádek souborů, které dostane jako parametry, což ale teď nebudeme
používat – bez pozičních argumentů totiž wc
provádí to samé se svým
standardním vstupem a na svůj standardní výstup vypisuje výsledek. Ve výchozím
nastavení směřují standardní vstup i výstup na terminál.
Když wc
spustíme, můžeme psát libovolný text, Zadávání ukončíme speciálním
znakem EOF
(End-of-file), který napíšeme stiskem Ctrl+D na prázdném
řádku. Tím ukončíme vstup a wc
provede svoji práci – vypíše dané počty.
Pokud bychom chtěli příkaz ukončit bez toho, aby vypsal výsledek, můžeme ho
násilně zastavit pomocí Ctrl+C.
Toto ale není příliš praktické použití, mnohem lepší by bylo přesměrovat na
vstup nějaký soubor. To uděláme pomocí operátoru šipky: Když zapíšeme
wc < soubor.txt
, tak přesměrujeme obsah zadaného souboru na standardní
vstup příkazu wc
. Zkuste si to. Stejně tak můžeme zápis převrátit a jako
první napsat přesměrování. Dokonce nemusíme ani okolo operátoru přesměrování
psát žádné mezery (lze tedy psát <soubor.txt wc
). Syntaxe je dost volná,
stačí si zvolit styl, který se vám bude nejvíce líbit.
Stejně jako vstup můžeme přesměrovat i výstup, to uděláme šipkou ukazující
na druhou stranu, směrem k souboru. Příkaz ls > seznam.txt
přepíše
soubor seznam.txt
a uloží do něj výstup z příkazu ls
, na terminálu
se v takovém případě žádný výstup neobjeví. Kdybychom namísto přepsání souboru
chtěli jenom připojit nové řádky na jeho konec, můžeme použít dvojitou šipku:
ls >> seznam.txt
.
Co když budeme chtít použít výstup jednoho příkazu jako vstup pro druhý? Určitě
bychom mohli použít pomocný soubor, třeba pomocí a > tempfile ; b < tempfile
, ale shell nám
nabízí mnohem elegantnější věc, a tou je takzvaná roura.
Roura se zapisuje jako svislá čára (na anglické klávesnici ji najdeme nad
Enterem) a funguje tak, že vezme standardní výstup příkazu nalevo od sebe
a použije ho jako vstup pro příkaz napravo. Zápis a < soubor | b | c
(nebo
ekvivalentní <soubor a|b|c
) znamená to, že spustíme
příkaz a
, kterému předáme na vstupu soubor a jeho výstup použijeme jako
vstup pro příkaz b
. Výstup příkazu b
pak použijeme jako vstup pro
c
a výstup c
zobrazíme na terminálu. Jednotlivé programy přitom
běží současně a mezivýsledky si rovnou předávají, ty tedy nezabírají žádné místo
na disku.
Pokud budete používat přesměrování do souboru, dejte si ale pozor na jednu věc.
Nelze najednou načítat a zapisovat stejný soubor, shell totiž jako první smaže
původní soubor (pokud používáme přesměrování jednou šipkou), a pak teprve by se
ho pokoušel načíst. Pozor na to hlavně při úpravách již hotového textu, dá se
takto nenávratně smazat několikahodinová práce.
Úkol 5 [1b]
Do souboru datum
vypište na první řádek „Dnes je:“ a na druhý aktuální
datum a čas v jakémkoliv formátu. Asi vám k tomu pomůže příkaz date
a pro
zkontrolování obsahu souboru můžete použít buď již zmíněný cat
, nebo
prohlížeč souborů less
– ten se ukončuje stiskem q
.
Úkol 6 [1b]
Spočtěte nějakým příkazem počet adresářů a souborů ve svém domovském adresáři
(kromě skrytých).
Úkol 7 [2b]
Napište příkaz využívající roury, který ze souboru soubor.txt
vezme
jedenáctou až třicátou řádku včetně a spočítá počet slov na nich. Můžete
předpokládat, že soubor.txt
je dostatečně dlouhý.
Úkol 8 [2b]
Vypište velikost v bajtech všech souborů v aktuálním adresáři, které obsahují
v názvu alespoň jednu číslici (nezapomeňte na skryté soubory).
Závěr
Dnes jsme si prošli základní příkazy a principy použitelné v bashi. Zopakujme
si všechny příkazy, které jsme se naučili:
- Navigace:
pwd
, cd
, ls
- Manipulace se soubory:
touch
, cp
, mv
, rm
, mkdir
, rmdir
- Obsah souborů:
cat
, head
, tail
, wc
- Další:
echo
, less
, date
- Manuál:
man
- Wildcardy, roury a přesměrování vstupu a výstupu.
Příští díl se již můžete těšit na některé pokročilejší UNIXové techniky,
my se budeme těšit na vaši účast. :-)
Jirka Setnička
Řešení