Skip Ribbon Commands
Skip to main content

Ondrej Sevecek's Blog

:

Engineering and troubleshooting by Directory Master!
Ondrej Sevecek's Blog > Posts > Naučte se používat uvozovky, apostrofy, složené závorky a herestring
srpen 18
Naučte se používat uvozovky, apostrofy, složené závorky a herestring

Jéé, našel jsem článek, co jsem psal před půl rokem a neuveřejnil...

Pokaždé, když tohle ukazuju, setkávám se s poměrně překvapenými výrazy. Možná bude dobře dát tady do kupy, třeba si to někdo přečte.

Řetězce v PowerShellu

Existuje několik možností, jak zadat řetězec v PowerShellu. Můžete to udělat takto:

# pomoci apostrofu (jednoducha uvozovka) - single quote
$text = 'hellow world'

# pomoci normalnich uvozovek - double quotes
$text = "hellow world"

# slozene zavorky - double brackets
$text = { hellow world }

# jednoduche uvozovky (apostrof) a zavinac - at sign
$text = @'
    hello world
'@

# normalni dvojite uvozovky a zavinac - at sign (herestring)
$text = @"
    hello world
"@

Akorát ten výsledek není stejný. Jednoduché uvozovky, neboli apostrof, a normální dvojité úvozovky se nazývají jednoduše string. Pokud tam přidáte ještě zavináč (at sign), tak se to nazývá here string. Složené závorky jsou specialita nazvaná ScriptBlock.

Rozdíl mezi apostrofem a uvozovkami

Cokoliv napíšete do apostrofů (jednoduchých uvozovek) se chápe prostě jako znaky. Uvnitř apostrofů neexistují žádné speciální znaky, kromě jednoho. Co když chcete dovnitř napsat apostrof? Musíte ho jednoduše zdvojit:

$message = 'I would like to say ''hello world'' to the world'

Výsledkem jsou jenom jedny apostrofy. Pokud do apostrofového řetězce vložíte například dvojité úvozovky, nemusíte se ničeho obávat, prostě tam normálně budou:

$message = 'I would like to say "hello world" to the world'

Zato pokud použijete normální uvozovky, má to trošku více možností. Uvnitř dvojitých úvozovek se vyhodnocují escape sekvence a nahrazují se hodnoty proměnných a složitějších výrazů. Podívejte se na následující příklad.

$age = 35
$name = 'Ondrej'

$message = "My name is $name and I am `t`t $age years old"
# result: My name is Ondrej and I am         35 years old

Uvnitř uvozovkového řetězce se vyhodnotí $ (dolar) znak a proměnné $age a $name a nahradí se svou hodnotou. Dále jsem tam rovnou vložil dvakrát escape sekvenci pro speciální znak TAB. Escape sekvence se dělá pomocí znaku zpětného apostrofu (zpětná jednoduchá uvozovka - tick), to je znak co máte úplně nalevo vedle jedničky pod ESC. Jiné speciální escape znaky, které jsou běžně používané jsou `n a `r, tedy konec řádku.

Jak vložíte do uvozovek jiné uvozovky? Musíte to zvnovu escapenout:

$message = "Moje prezdivka je `"ondass`" a me se docela libi"

Jak je vidět, narozdíl od jednoduchých apostrofů, uvnitř nichž jste apostrof museli zdvojit, tady musíte uvozovky escapenout.

Nahrazování proměnných a výrazů uvnitř uvozovek

Jak jsme říkali, řetězce apostrofové samy proměnné nenahrazují. Hodí se to tedy obvykle více jako obecný znak pro ohraničování "čehokoliv". Zatímco uvozovkové řetězcové konstanty mají právě výhodu (někdy to právě není výhoda), že nahrazují proměnné, ale umí nahradit i složitější výrazy.

Samozřejmě pozor na to, že PowerShell musí být schopen poznat, co je jméno proměnné a co není:

$age = 35
$name = 'Ondrej'

$message = "My name is $name and I am $ageYears old"
# result: My name is Ondrej and I am old

Jak je vidět, tady jste neoddělili slovo Years od jména proměnné, takže si PowerShell myslel, že tam chcete vložit hodnotu proměnné $ageYears, která neexistuje.

To se dá vyřešit právě pomocí nahrazování celých výrazů:

$age = 35
$name = 'Ondrej'

$message = "My name is $name and after 20 years, I will be $($age + 20)years old"
# result: My name is Ondrej and after 20 years, I will be 55years old

Jasné? PowerShell vidí uvnitř znak dollaru. Za ním následuje závorka, takže všechno co je uvnitř se nejprve vyhodnotí. V tomto případě nejen jméno proměnné, ale rovnou výpočet. Můžete volat dokonce cmdlety, příkazy a cokoliv, co je prostě PowerShell výraz.

Já osobně nerad používám uvozovky, raději dovnitř vkládám hodnoty pomocí operátoru -f (tedy [String]::Format), protože je to podle mě přehlednější a méně náchylné k chybám, kdy si do uvozovkového řetězce z nepozornosti vložíte dolar jako součást nějakého textu. Typicky heslo Pa$$w0rd :-)

Abyste nemuseli přemýšlet o nahrazování, aneb herestring

Takže jak jsme viděli, v obou formách řetězců se něco nahrazuje. Uvnitř apostrofů sice jenom znak dvojitého apostrofu, ale i tak je to dost. Někdy chcete do řetězce vložit prostě cokoliv. Typickým příkladem je možnost přímo do PowerShellu vložit C# kód, který to umí samo zkompilovat a pustit (jako jsem třeba nedávno použil v případě porovnání na null). Jenže to by byla strašná dřina kontrolovat, co tam musíte opravit, aby to fungovalo správně.

Od toho jsou právě ony herestringy. Prostě dáte navíc zavináč a můžete si psát co chcete. Má to samozřejmě jedno omezení. Here string začíná @', ale tohle musí být poslední znak na řádku. A končí zase opačně apostrof-zavináč, tedy '@, ale tady to musí být vůbec první znak na řádku. Ani mezera před ním nemůže být.

Aby toho nebylo málo, here string můžete udělat i za použití uvozovek, tedy @" a "@. V takovém případě se uvnitř vyhodnocují escape sekvence a proměnné. Na co to tedy je? No na to, že uvnitř můžete používat volně uvozovky, které tím pádem nemusíte escapeovat.

Podivný řetězec typu ScriptBlock

Ono to vypadá divně, když tvrdím, že to je řetězec. Asi to každý chápe jako blok PowerShell kódu, že? Jenže on to je opravdu jen řetězec. Přijme to cokoliv, co tam napíšete. Není to kompilované. Jediné co to dělá, je že to musí mít korektní PowerShell syntaxi. Následující dva příklady jsou podivné, ale od toho je tento článek

# although this is a valid PowerShell script
# when you run it, it will probably fail because you do not have
# a hello program with world parameter available
$validPSstr = ' hello world '
$validPSsb = { hello world }
& $validPSstr
& $validPSsb

# this is an invalid PowerShell code, because if requires
# brackets for its condition
$invalidPDstr = ' if error then fail '
$invalidPD = { if error then fail }

V prvním případě jsem nadefinoval dvakrát ten stejný PowerShell kód, který následně spouštím pomocí operátoru ampersand &. Z pohledu syntaxe je to naprosto v pořádku PowerShell kód. Akorát se podívejte na tu chybu. PowerShell to pochopil tak, že chcete spustit program hello s parametrem world. Což nejspíš neexistuje.

Ve druhém případě vám projde to přiřazení do řetězce, protože tam se nekontroluje syntaxe. Ale právě v případě složených závorek (double bracket) to neprojde. Byť to možná vypadá podobně, klíčové slovo if musí být následováno závorkami, takže tohle není platný PowerShell kód.

Shrnutí

Existují tedy tyto typy řetězců:

  • jednoduché uvozovky (apostrof) - uvnitř se v podstatě nic nenahrazuje, kromě dvojitého apostrofu
  • normální uvozovky (dvojité uvozovky) - uvnitř se nahrazují escape sekvence pomocí znaku zpětného apostrofu (tick) a hodnoty proměnných a obecně výrazů začínajících znakem dollar $.
  • here string - nenahrazuje se nic v případě apostrofového, v případě uvozovkového se uvnitř dá použít bez problémů uvozovka.
  • ScriptBlock - taky je to vlastně jen text. Akorát se mu kontroluje PowerShell syntaxe. Neznamená to, že by příkazy musely existovat. Prostě až se bude spouštět, třeba to klapne :-)

Cvičení na závěr

A zkuste se zamyslet, co asi udělá toto (když to dělá chybu, je to tam tak schválně :-)):

$jmeno = 'Ondrej'
$vek = 35

'Moje jmeno je $jmeno a vek je $vek'

"Moje jmeno je $($jmeno) a vek je $vek"

"Vsechny procesy v retezci $(get-process). To je ale hruuuuza"

"Vsechny procesy v retezci $(get-process svc* | Out-String). Neni to aspon trosku lepsi?"

"Heslo je: Pa$$w0rd"

"Moje jmeno je ''$jmeno''"

'Moje jmeno je `'$jmeno`''

"Co treba ""tohle"""

"Co treba `"jinak`""

'Pujde sem vlozit TAB-`t`t-?'

"Pujde sem vlozit TAB-`t`t-?"

'Jmeno zarovnane doprava {0,20}.' -f $jmeno

"Co tohle jmeno {$jmeno}"

"Co tohle jmeno {$jmeno} a {0}" -f $vek

"Co tohle jmeno `{$jmeno`} a {0}" -f $vek

"Co tohle jmeno {{$jmeno}} a {0}" -f $vek

'Vsechny procesy v retezci {0}. Takto mi to pripadne neprehlednejsi.' -f (get-process svc* | Out-String)

 

Comments

Re: Naučte se používat uvozovky, apostrofy, složené závorky a herestring

>> Jak vložíte do uvozovek jiné uvozovky? Musíte to zvnovu escapenout:
>> $message = "Moje prezdivka je `"ondass`" a me se docela libi"
>> Jak je vidět, narozdíl od jednoduchých apostrofů, uvnitř nichž jste apostrof museli zdvojit, tady musíte uvozovky escapenout.

Tohle ale take funguje. neni treba ESCape ?!?
$message = "Moje prezdivka je ""ondass"" a me se docela libi"
VasekB on 20.8.2014 22:47

Add Comment

Title


Pole Title nemusíte vyplňovat, doplní se to samo na stejnou hodnotu jako je nadpis článku.

Author *


Pole Author nesmí být stejné jako pole Title! Mám to tu jako ochranu proti spamu. Roboti to nevyplní dobře :-)

Body *


Type number two as digit *


Semhle vyplňte číslici dvě. Předchozí antispemové pole nefunguje úplně dokonale, zdá se, že jsou i spamery, které pochopily, že je občas potřeba vyplnit autora :-)

Email


Emailová adresa, pokud na ni chcete ode mě dostat odpověď. Nikdo jiný než já vaši emailovou adresu neuvidí.

Attachments