Pro fanouška Linuxu je to denní chléb a jedna z nejpropracovanějších funkcí operačního systému. My na Windows na to už ale občas zapomínáme, máme totiž nějaký ten grafický program úplně na všechno. Řeč je samozřejmě o příkazové řádce.
Byť si pod ní mnozí představí zaprášenou minulost a nevkusný MS-DOS, bylo by to krajně nefér, ve skutečnosti je to totiž všechno naopak. Ostatně, nebýt příkazové řádky, svět, jak jej dnes známe, by vůbec nemohl existovat.
Bez nadsázky! Ta hezká okénka aplikací se stíny, všemožnými efekty a s vyhlazenou typografií jsou vlastně jen tou nejsvrchnější vrstvičkou počítačového UI. UI, které hraje klíčovou roli na mobilech a běžných desktopech, nicméně na serverech, superpočítačích a dalších specializovaných mašinách, které řídí svět, dodnes vládnou blikající kurzor a sofistikované textové aplikace.
Dnes ovládneme kurzovní lístek ČNB
Ačkoliv jsou tedy doby MS-DOSu ty tam, černá obrazovka právem straší i v těch nejnovějších Windows. Ovšem pozor, tím opravdu nemám na mysli morálně zastaralou příkazovou řádku cmd.exe, ale samozřejmě moderní textový interpret PowerShell, který v sobě skrývá stovky a stovky příkazů – tzv. cmdletů – a docela mocný skriptovací nástroj.
Toto bude výsledek dnešní práce v PowerShellu. Tak hurá do toho
A protože nedělní večery patří bastlení, zkusíme si dnes v PowerShellu napsat jednoduchý program na zjišťování ceny chorvatských kun i evropského eura podle aktuálního kurzovního lístku České národní banky. V úvodu si ale nejprve připomeneme samotnou práci v textovém prostředí na několika příkladech.
Nejsem žádná lama, teleportuj mě rovnou na povídání o skriptu, který se bude dotazovat ČNB na kurzy měn. Jasně, žádný problém, klikni sem.
Pokračování 2 / 8
Pětku, nebo naopak Sedmičku?
Jelikož je PowerShell integrální součástí všech novějších verzí Windows, naše kurzovní dotazovátko bude fungovat bez nutnosti instalace nějakého dalšího prostředí – třeba tolik oblíbeného interpretu jazyka Python.
Ovšem pozor, aby to bylo pro zelenáče co nejvíce frustrující, ve výchozím stavu se ve Windows nachází povážlivě stárnoucí pátá generace PowerShellu, ačkoliv Microsoft paralelně vyvíjí už 7. řadu tohoto interpretu a jazyka. Sedmička je k dispozici na GitHubu a k mání je nejen pro Windows, ale také pro mnohé linuxové systémy a samozřejmě i macOS.
Nainstaluj si PowerShell 7, žadoní po mně vestavěný PowerShell 5 ve WIndows 11
Náš skript sice poběží v obou interpretech, jsou ale mezi nimi místy docela dramatické rozdíly, a tak by se měl zelenáč rozhodně pustit spíše do toho nejnovějšího. Je to vlastně obdobný rozkol jako v případě Pythonu 3 a jeho starší generace 2, která bohužel dodnes straší v mnoha webových návodech a rigidnějších linuxových distribucích, takže kdejaký začátečník jen nechápavě kroutí hlavou.
Špatně mi to zobrazuje češtinu!
Webu a linuxovým systémům dnes vládne kombinace Unicode/UTF-8, na Windows to ale bylo vždy krapet složitější. Pokud vám bude v PowerShellu náš skript v UTF-8 špatně zobrazovat české znaky, bude to pravděpodobně právě používáním starší 5. generace, která je součástí Windows, a proto se jmenuje Windows PowerShell.
Špatné kódování češtiny v předinstalovaném Windows PowerShellu (verze 5) a funkční Unicode/UTF-8 v PowerShellu 7. Všimněte si odlišných ikon programů
V takovém případě by měla být nejjednodušším řešením instalace nového PowerShellu 7. Vřele také doporučují zahodit výchozí Příkazovou řádku (CMD/Windows Console Host) a nahradit ji moderním rozhraním Windows Terminal.
Změna výchozího textového rozhraní na Windows Terminal a v něm spuštěný PowerShell 7 a náš skript s bezchybnou češtinou v UTF-8
V jeho konfiguraci pak stačí nastavit, aby se rozhraní Windows Terminal používalo ve výchozím stavu pro všechny textové programy, ať už je spustíte jakýmkoliv způsobem (třeba skrze dialog WIN+R).
PowerShellem ovládnete celý počítač
PowerShell přináší uživateli ohromné množství komplexních příkazů – takzvaných cmdletů –, kterými můžete spravovat do nejmenšího detailu jak celý operační systém Windows, tak i další úlohy na počítači.
Aby byla práce s PowerShellem dostatečně univerzální, k mnoha tradičním příkazům ještě z dob zmíněného MS-DOSu nabízí přezdívky, které se naopak prosadily v linuxovém a obecně posixovém světě včetně macOS.
V PowerShellu funguje jak dosovský dir, tak unixový ls
Výpis obsahu aktuálního adresáře tedy provede jak dosový příkaz dir, tak univerzálnější ls. Textové okno zase smaže jak cls, tak unixové clear a v obou světech můžeme propojovat výstupy a vstupy programů skrze tzv. rouru |.
Pokračování 3 / 8
Get-command ukáže stovky příkazů
Základních příkazů, cmdletů a přezdívek v PowerShellu jsou stovky a je až s podivem, že na webu neexistuje nějaký oficiální a dostatečně přehledný adresář.
Výpis podporovaných příkazů pomocí get-command
Ty základní najdete třeba zde, tady a všechny ostatní a nainstalované na vašem operačním systému odkryje editor powershellových skriptů ISE, nebo prostý příkaz:
get-command
Okénko se zaplní ohromným množstvím dostupných povelů, pro krokový výpis proto můžeme použít zmíněnou rouru |, kdy výstup přesměrujeme do dalšího programu more, jehož jediným účelem je výpis vždy jen do zaplnění obrazovky:
get-command | more
Get-help zobrazí nápovědu ke každému příkazu
Jak mám ale vědět, co který příkaz ve výpisu get-command dělá? Nu, stačí jeho název zkopírovat do Googlu, anebo použít cmdlet nápovědy get-help, který je komplexnější analogií unixového man.
Nápověda pomocí get-help
Zaujal mě třeba program get-process. Jeho základní dokumentaci proto zobrazím zavoláním:
get-help get-process
A mám jasno, get-process vypíše tabulku s běžícími procesy. Každý z nich má své jméno a ID, pomocí kterého s ním mohu dále pracovat. Výpis ale mohu i jednoduše filtrovat.
Pokračování 4 / 8
Get-process je textový správce procesů
Takže kdybych chtěl získat seznam procesů, jejichž název odpovídá masce not*, stačí zadat:
get-process not*
Hvězdička na konci představuje libovolný pokračující text, a jelikož jsem před chvíli spustil Poznámkový blok, jehož proces se jmenuje Notepad, vypíše se mi v tabulce.
Ale fuj, to je spuštěných Poznámkových bloků
Z představy, že mi na počítači běží Poznámkový blok, jsem poněkud nervózní, a tak jej zabiju příbuzným příkazem:
stop-process čísloprocesu
Anebo klidně hromadně skrze masku s hvězdičkou:
stop-process -processname not*
Kill them all...
Přesměrování výstupu do souboru
Textový výpis nemusí skončit jen v příkazové řádce, ale můžete jej uložit i do souboru pro další zpracování. Nejjednodušším způsobem jsou samozřejmě znaky pro přesměrování výstupu > a >>.
Uložení surového výstupu do textového souboru
Ten první výstup zapíše do nového souboru, takže kdybych potřeboval uložit seznam běžících procesů do procesy.txt, stačí zadat:
get-process > procesy.txt
Pokud znak použiji dvakrát:
get-process >> procesy.txt
Soubor se nepřepíše, ale výstup se zapíše na jeho konec, což se hodí pro případy, kdy třeba sledujeme vývoj nějaké proměnné a v souboru máme celou její historii pěkně po jednotlivých řádcích.
Pokračování 5 / 8
PowerShell umí uložit výstup do CSV i HTML
Primitivní přesměrování zvládne každé textové prostředí nejen na Windows, ale i na unixových systémech, PowerShell nicméně obsahuje i pár unikátních specialit pro formátovaný výstup.
Uložení formátovaného výstupu do HTML
Třeba cmdlet export-csv, který dokáže tabelovaný výstup, který do něj přesměrujeme skrze rouru, uložit do CSV:
get-command | Export-Csv -Path prikazy.csv
A jelikož žijeme v době webové, PowerShell umí textový výstup převést dokonce i do HTML, který poté mohu opět přesměrovat do souboru:
get-command | ConvertTo-Html | Out-File prikazy.html
V čem programovat powershellové skripty
Fajn, takže to bychom měli demonstraci základní práce se samotným interpretem PowerShellu, teď už se ale pojďme podívat na jeho skriptování. Program napsaný v PowerShellu je běžný textový soubor s příponou ps1.
PowerShell ISE a náš dnešní skript
Můžete tedy použít libovolný textový editor včetně Poznámkového bloku. Součástí Windows by ale mělo být i jednoduché vývojové prostředí PowerShell ISE. Sice má grafické rozhraní jak z přelomu století, nabízí ale přinejmenším našeptávač příkazů.
Visual Studio Code s doplňkem PowerShell a náš dnešní skript
Další možností je bezplatný editor Visual Studio Code, který má k dispozici doplněk pro programování v PowerShellu přímo od Microsoftu. Nabídne se sám k instalaci, jakmile v editoru otevřete libovolný soubor s příponou ps1.
Pokračování 6 / 8
Invoke-WebRequest je textový HTTP klient
Základem našeho programu bude cmdlet Invoke-WebRequest, což je vlastně docela mocný textový HTTP klient, který se chová podobně jako třeba program curl na linuxových a unixových systémech.
Stažení kurzovního lístku pomocí cmdletu Invoke-WebRequest
Pomocí tohoto příkazu stáhneme stručný kurzovní lístek v textovém formátu z webu České národní banky. Kdybychom to chtěli provést přímo v příkazové řádce PowerShellu, stačí zavolat příkaz:
Invoke-WebRequest https://www.cnb.cz/cs/financni_trhy/devizovy_trh/kurzy_devizoveho_trhu/denni_kurz.txt -OutFile kurzy.txt
Samotný název cmdletu je docela dlouhý, a tak můžeme použít i jeho zkratku – alias iwr:
iwr https://www.cnb.cz/cs/financni_trhy/devizovy_trh/kurzy_devizoveho_trhu/denni_kurz.txt -OutFile kurzy.txt
V obou případech se soubor uloží do aktuálního adresáře pod názvem kurzy.txt
Dekódujeme kurzovní lístek
Soubor je připravený pro strojové zpracování, každá z měn je totiž na různém řádku ve formátu:
země|měna|množství|kód|kurz
Takže záznam pro euro a páteční odpoledne vypadal takto:
EMU|euro|1|EUR|24,605
V našem skriptu zavoláme cmdlet podobným způsobem, nicméně jeho odpověď uložíme jako objekt do stejnojmenné proměnné. Proměnné v PowerShellu uvozuje znak $, takže příkaz bude vypadat takto:
$odpoved = Invoke-WebRequest https://www.cnb.cz/cs/financni_trhy/devizovy_trh/kurzy_devizoveho_trhu/denni_kurz.txt
Pokud vše proběhlo tak, jak mělo, v objektu $odpoved je nyní kompletní odpověď HTTP serveru včetně hlaviček, nás ale zajímá obsah odpovědi, a tak PowerShellu přikážeme, ať jej převede do prostého textového řetězce, který uložíme do další proměnné $text:
$text = $odpoved.Content.ToString()
Kompletní text bychom mohli vypsat do výstupu příkazové řádky třeba takto:
Write-Output $text
A takhle bude celá sekvence vypadat v praxi
My si ale v dalším kroku dlouhý řetězec rozdělíme do pole po jednotlivých řádcích. Slouží k tomu metoda split, jejímž parametrem je dělící znak. Kurzovní lístek používá pro zalomení řádků standardní ASCII znak LF s číselným šestnáctkovým kódem 0x0A, a tak jej použijeme jako parametr:
$radky = $text.split(0x0A)
Jelikož nyní máme jednotlivé měny včetně úvodní hlavičky hezky uložené v poli, můžeme jej projít položku po položce. Slouží k tomu příkaz foreach:
foreach($radek in $radky){
Write-Output "Řádek: $radek"
}
Úryvek výše projde pole a vypíše všechny řádky do standardního výstupu uvedené slovíčkem „Řádek:“ pro kontrolu, že se kompletní textový řetězec rozřezal tak, jak měl.
Nyní už umíme rozlišovat jednotlivé řádky
Jak už jsme si řekli výše, takový řádek má podobu třeba:
EMU|euro|1|EUR|24,605
Každý z nich bychom tedy mohli dále rozřezat na jednotlivé dílky do pole, přičemž nožem tentokrát bude znak |:
$mena = $radek.split("|")
Namísto původního strojového řádku konečně vše vypíšeme mnohem přívětivějším způsobem:
foreach($radek in $radky){
$mena = $radek.split("|")
Write-Output "$($mena[2]) $($mena[1]) ($($mena[0])) stojí $($mena[4]) korun českých"
}
Všimněte si, že k jednotlivým dílkům pole přistupujeme stejně jako v ostatních programovacích jazycích skrze index v hranatých závorkách (index začíná vždy od nuly, nikoliv od jedničky) a při skládání hotového textového řetězce, který se jako celek vypíše do výstupu příkazové řádky PowerShellu, použijeme zápis ve formátu $($mena[2]). To je velmi důležité, jinak by se totiž do textu vložila celá proměnná $mena a za ní jako prostý text [2].
Srozumitelnější rozpis jednotlivých kurzů. Pro jednoduchost příkladu jsem neošetřil první dva informativní řádky a závěrečné zalomení. To až později
Pokračování 7 / 8
Skript vypíše jen ty kurzy, o které máme zájem
Tím by mohl náš program skončit, my jej ale přece jen ještě trošku vylepšíme. Skript se bude jmenovat kurzy.ps1 a namísto vypisování všech měn už v úvodu určíme, které nás zajímají uvedením kódu měny nebo jiného políčka v řádku.
Když nás tedy bude zajímat třeba euro, dolar a chorvatská kuna, spustíme skript z příkazové řádky takto:
.\kurzy.ps1 USD EUR kuna
Anebo třeba jen:
.\kurzy.ps1 koruna
Přičemž z kurzovního lístku ČNB se poté vyberou všechny koruny v nabídce: dánská, islandská, norská a švédská. To je chytré, viďte?
Čteme argumenty skriptu
Aby to tak mohlo fungovat, musíme se dostat k poli argumentů skriptu, které je uložené ve vestavěné proměnné $args. My se proto na začátku programu zeptáme, jestli toto pole obsahuje alespoň jednu položku, no a pokud ne, vypíšeme chybovou zprávu a příkazem Break skript ukončíme.
Pokud nebude mít skript žádný argument, vynadáme uživateli a skript ukončíme
V běžných programovacích jazycích bychom použili porovnávací operátor >= (větší, nebo rovno), v PowerShellu se ale používá trošku jiný zápis. Jako operátor >= zde slouží -ge (pod odkazem najdete i všechny ostatní).
Kontrola na počet argumentů skriptu by tedy mohla vypadat třeba takto:
if($args.length -ge 1){
Write-Output "Vypisuji kurzy podle ČNB"
Write-Output "------------------------"
}
else{
Write-Output "Ale ne, musíš zadat kódy hledaných měn!"
Break
}
V závěrečné smyčce našeho programu pak už jen projdeme opět pomocí foreach pole s argumenty a dalším operátorem -contains zjistíme, jestli se nevyskytuje v některém z dílku pole $mena, které právě analyzujeme. A pokud tomu tak bude, kurz měny opět hezky rozepíšeme do standardního výstupu – v tomto kontextu do příkazové řádky.
Celý skript v PowerShellu od hlavy až k patě vypadá takto:
if($args.length -ge 1){
Write-Output "Vypisuji kurzy podle ČNB"
Write-Output "------------------------"
}
else{
Write-Output "Ale ne, musíš zadat kódy hledaných měn!"
Break
}
$odpoved = Invoke-WebRequest https://www.cnb.cz/cs/financni_trhy/devizovy_trh/kurzy_devizoveho_trhu/denni_kurz.txt
$text = $odpoved.Content.ToString()
$radky = $text.split(0x0A)
foreach($radek in $radky){
$mena = $radek.split("|")
foreach($kod in $args){
if($mena -contains $kod){
Write-Output "$($mena[2]) $($mena[1]) ($($mena[0])) stojí $($mena[4]) korun českých"
}
}
}
Pokračování 8 / 8
Ale ne, PowerShell nechce spustit náš skript
Když nyní skript spustíte ve svém PowerShellu ve Windows Terminalu, dost možná se zobrazí rudé chybové hlášení s tím, že skript není důvěryhodný, a tak jej interpret odmítl spustit. PowerShell je v tomto směru velmi přísný.
Skript nelze v daném kontextu spustit
Abychom si to co nejvíce usnadnili, aktuálnímu uživateli Windows (nám) dáme práva ke spuštění všech skriptů, což je pro účely experimentování prakticky nezbytné:
Set-ExecutionPolicy -Scope CurrentUser Unrestricted
Povolení spouštění všech skriptů aktuálního uživatele
Kdybyste později chtěli spouštění opět zakázat, respektive omezit jen na podepsané skripty, stačí analogicky zavolat:
Set-ExecutionPolicy -Scope CurrentUser AllSigned
Webový klient je pouze začátek
Dnes jsme si ukázali, že příkazová řádka na Windows opravdu není jen ten prehistorický cmd.exe, který neumí prakticky nic a je to jen připomínka dávných dob. PowerShell je naopak velmi mocný nástroj, který s operačním systémem provede téměř cokoliv.
Náš kurzovní dotazovač v PowerShellu, který se ptá webu ČNB
My jsme si dnes vyzkoušeli jen jeho cmdlet pro práci s HTTP klientem, někdy příště si ale v textové řádce na Windows vyzkoušíme i hromadné operace s obrázky, konvertování videa a další fígle, na které vůbec nepotřebujete nějaký těžkotonážní grafický program.
Tento článek je součástí balíčku PREMIUM+
Odemkněte si exkluzivní obsah a videa bez reklam na devíti webech.
Chci Premium a Živě.cz bez reklam
Od 41 Kč měsíčně