Linux: Kniha kouzel, vanilková příchuť 2.14 (15. července 2022)
Veškerá moc příkazové řádky/příkazového řádku přehledně, pro začátečníky i pokročilé

10. Perl: základy

Řada 2.x vanilkové příchuti Linuxu: Knihy kouzel je od 15. července 2022 do 1. března 2025 ve stavu dlouhodobé pasivní údržby; nahlášené chyby budou opravovány, ale aktivní vývoj se již věnuje jiným projektům. Máte-li zájem pokračovat v tvorbě Linuxu: Knihy kouzel pro novější verze linuxových operačních systémů, kontaktujte autora nebo rovnou vytvořte odnož.

1. Úvod

Perl je skriptovací jazyk určený především pro zpracování textu. Mezi programátory je velmi oblíbený a rozšířený, má však špatnou pověst, protože je multisyntaktický a pro neodborníka velmi špatně čitelný. Přesto je velmi užitečný a při využití jen malé podmnožiny jeho vlastností je snadné v něm začít programovat.

Perl je ale také zákeřný programovací jazyk, v němž je podmínka „if (false)“ splněna, funkce length() aplikovaná na osmnáctiprvkové pole vrací hodnotu 2, připojovaný zdrojový soubor musí končit příkazem „1;“, proměnné se nejčastěji deklarují klíčovým slovem „my“ a příkaz náhrady „s/.$/@/“ provedený nad řetězcem "X\n\n\n" nikdy neskončí výsledkem "X\n\n@" jako v GNU Sedu, ale jedním z výsledků "X\n\n\n" (bez modifikátoru), "X\n@\n" (s modifikátorem „s“) nebo „X\n@@“ (s modifikátory „gs“); ke stejnému chování jako v Sedu ho však nedonutíte.

Kapitoly vanilkové příchuti Linuxu: Knihy kouzel zaměřené na Perl se omezují na bezpečnou podmnožinu jeho funkcionality, čímž vám umožní začít z jeho moci těžit velmi rychle a s minimem nutných znalostí a vyhýbat se přitom většině zákeřných pastí. (Pronikat do „hlubin Perlu“ můžete později. Nejdřív naprogramujte, co potřebujete.)

Tato kapitola nepokrývá moduly, objektově orientované programování a velkou část užitečných knihovních funkcí (např. práci s databázemi).

Poznámka: Všechna zaklínadla v této kapitole předpokládají, že máte nainstalovaný balíček DEB Linuxu: Knihy kouzel a skripty budete spouštět výhradně příkazem „lkk perl“. Informace, jak takové skripty zprovoznit bez něj, najdete v repozitáři Linuxu: Knihy kouzel na GitHubu.

2. Definice

  • Skalár je dynamicky typovaná hodnota, která může být řetězec, číslo, ukazatel na nějaký objekt nebo zvláštní nehodnota undef. Výchozí hodnotou skalárů je undef. Jednotlivé skaláry se symbolizují znakem „$“.
  • Pole (array, list) je uspořádaný kontejner skalárů indexovaný celými čísly 0, 1, 2 atd. Pole se symbolizují znakem „@“ a pro přístup k jejich prvkům se používá index (či seznam indexů) v hranatých závorkách „[]“. (Na rozdíl od GNU awk, v Perlu se prvky polí číslují vždy od nuly.) Výchozí hodnotou je prázdné pole.
  • Asociativní pole (hash) je neuspořádaný kontejner skalárů (hodnot) indexovaný libovolnými řetězci (klíči). Symbolizuje se znakem „%“. Přístup k prvkům pole se vyznačuje použitím klíče (či seznamu klíčů) ve složených závorkách „{}“. Asociativní pole se inicializují poli či seznamy se sudým počtem prvků, kde se první prvek každé dvojice interpretuje jako klíč a druhý jako odpovídající hodnota. V seznamech se pak asociativní pole na takový seznam rozloží. Výchozí hodnotou je prázdné asociativní pole.

Je v pořádku mít vedle sebe proměnné „$x“, „@x“ a „%x“ a funkci „x()“, jsou to čtyři nezávislé věci. Konstanty však sdílejí „jmenný prostor“ s funkcemi.

  • Ukazatel (reference, v češtině obvykle nazývaný „odkaz“) je skalár, který odkazuje na nějaký objekt v paměti (skalár, pole, funkci, regulární výraz atd.). Přístup k odkazovanému objektu se získává dereferencí ukazatele. Operace, při kterých ukazatel není výslovně dereferencován, se týkají ukazatele jako takového.
  • Seznam je dočasný objekt příbuzný poli; zadává se výčtem prvků v kulatých závorkách, např. „(1, $b, 3)“. Kulaté závorky se nepoužijí, pokud je seznam bezprostředně obalen dalšími kulatými nebo hranatými závorkami. V téměř všech kontextech je seznam zaměnitelný s polem — kde se očekává pole, můžete uvést seznam, a naopak kde se očekává seznam, můžete uvést pole.
  • Důležitou vlastností seznamů je zplošťování — když v seznamu uvedete vnořený seznam, pole nebo asociativní pole, to se obvykle rozvine na všechny svoje prvky v odpovídajícím pořadí, jako byste je uvedl/a přímo. Nespoléhejte se však na zplošťování při volání systémových a knihovních funkcí (může být ovlivněno tzv. prototypem funkce) a v seznamech stojících na levé straně operátoru přiřazení (tam funguje trochu jinak).
  • Proud je objekt reprezentující soubor na disku nebo rouru vedoucí do jiného procesu. Umožňuje číst či zapisovat data, a to v textovém nebo binárním režimu.
  • Řetězec bajtů je každý řetězec, který obsahuje jen znaky s kódovou hodnotou 0 až 255. Takový řetězec může být bez konverze zapsán do souboru v binárním režimu. Všechny řetězce načtené v binárním režimu jsou řetězce bajtů.

3. Zaklínadla: Základní

3/1 Proměnné a konstanty

@deklarovat místní proměnnou typu skalár/pole/asociativní pole#1 (1)
my $identifikátor [= inicializace];
my @identifikátor [= inicializace];
my %identifikátor [= inicializace];
@deklarovat trvanlivou proměnnou#2 (2)
state $@%identifikátor [= inicializace];
@deklarovat globální proměnnou#3 (3)
our $@%identifikátor [= inicializace];
@deklarovat konstantu typu skalár/seznam#4 (4)
use constant identifikátor => inicializace;
use constant identifikátor => (inicializace);
@do konce bloku překrýt globální proměnnou#5 (5)
local $@%identifikátor = nová-hodnota;

3/2 Skaláry a undef

@má skalár hodnotu? (tzn. není undef)#1
defined($skalár)
@přečíst skalární proměnnou#2
$identifikátor
@přiřadit skalární proměnné hodnotu/undef#3
$identifikátor = hodnota
$identifikátor = undef
@přečíst skalární konstantu (obecně/příklady)#4 (6)
(identifikátor)
printf("Hodnota konstanty je: %d\n", (konstanta));
print(konstanta);
printf("V asoc. poli je %s\n", $asocPole{(konstanta)});
@zjistit typ skaláru#5 (7)
typy($skalár)⊨ "s"
@vrátit první ze skalárů, který má hodnotu#6 (8)
skalár [// další-skalár]

3/3 Volání funkcí

@zavolat funkci (obecně/příklady)#1 (9)
identifikátor_funkce(seznam,parametrů)
funkce()
funkce(1, $b, undef, 3)
@zavolat funkci přijímající blok příkazů (obecně)#2 (10)
(identifikátor_funkce {
příkaz bloku;
} [seznam,parametrů])
@zavolat funkci přijímající blok příkazů (příklad)#3
my @hodnoty = (map {
$ARG + 1;
} @část1, -1, @část2);
@předat řízení do funkce#4 (11)
goto &identifikátor_funkce;

3/4 Definice funkcí

@definovat funkci#1 (12)
sub identifikátor_funkce [(prototyp)]
{
[typy(@ARG) =~ /\Aregulární-výraz\z/ or croak("chybové hlášení");]
[příkazy]
}
@definovat funkci vracející přiřaditelný objekt#2 (13)
sub identifikátor_funkce [(prototyp)] : lvalue
{
[typy(@ARG) =~ /\Aregulární-výraz\z/ or croak("chybové hlášení");]
[příkazy]
}
@pole parametrů uvnitř definice funkce#3 (14)
@ARG
@deklarovat prototyp funkce před definicí#4
sub identifikátor_funkce (prototyp);
@definovat funkci přijímající blok příkazů#5 (15)
^sub identifikátor_funkce (&@);
sub identifikátor_funkce (&@)
{
[typy(@ARG) =~ /\ACregulární-výraz\z/ or croak("chybové hlášení");]
my $id = shift(@ARG);
[příkazy]
}

3/5 Komentáře

@komentář do konce řádku#1
[normální obsah řádky] # obsah komentáře
@víceřádkový komentář#2 (16)
=begin comment
obsah komentáře (i víc řádků)
=end comment
=cut

3/6 Volání příkazů /bin/sh

@zavolat příkaz interpretu /bin/sh (obecně/příklad)#1 (17)
system("text příkazů");
system("x=3; x=\$((x + 1)); echo \$x");
Návratový kód procesu získáte jako „($CHILD_ERROR >> 8)“.
@+ zachytit jeho std. výstup po řádkách do pole#2
[my @výstup =] do {use open("IN", ":utf8"); local $RS = "\n"; my @x = array(readpipe("text příkazů")); chomp(@x); @x;};
Návratový kód procesu získáte jako „($CHILD_ERROR >> 8)“.
@+ zachytit jeho std. výstup do jednoho řetězce#3
[my $výstup =] do {use open("IN", ":utf8"); local $RS = undef; scalar(readpipe("text příkazů"));};
Návratový kód procesu získáte jako „($CHILD_ERROR >> 8)“.
@+ zachytit jeho std. výstup binárně do řetězce bajtů#4
[my $výstup =] do {use open("IN", ":raw"); local $RS = undef; scalar(readpipe("text příkazů"));};
Návratový kód procesu získáte jako „($CHILD_ERROR >> 8)“.
@+ zachytit jeho std. výstup textově po záznamech ukončených „\0“ do pole#5
[my @výstup =] do {use open("IN", ":utf8"); local $RS = "\x{0}"; my @x = array(readpipe("text příkazů")); chomp(@x); @x;};
Návratový kód procesu získáte jako „($CHILD_ERROR >> 8)“.
@+ zachytit jeho std. výstup do pole obecně#6 (18)
[my @výstup =] do {use open("IN", ":režim-čtení" ); local $RS = nastavení-oddělovače; my @x = array(readpipe("text příkazů")); chomp(@x); @x;};
Návratový kód procesu získáte jako „($CHILD_ERROR >> 8)“.

3/7 Operace s čísly

@dělení (celočíselné/reálné/příklad celočíselného)#1 (19)
(div(dělenec, dělitel))[0]
dělenec / dělitel
my ($podíl, $zbytek) = div(5, 2);⊨ (2, 1)
@absolutní hodnota#2
abs(skalár)
@zaokrouhlit na nejbližší celé číslo#3
^use POSIX;
x >= 0 ? POSIX::floor(0.5 + x) : -POSIX::floor(0.5 - x)
@zaokrouhlit k nule#4
int(skalár)
@vygenerovat pseudonáhodné celé číslo 0 ≤ y < maximum#5
int(rand() * maximum)
@vygenerovat pseudonáhodné celé číslo 0 ≤ y < 4 294 967 296#6
int(rand() * 4294967296)
@nastavit počáteční „semínko“ generátoru pseudonáhodných čísel (na hodnotu/podle času)#7
srand(x);
srand(time());
@druhá odmocnina/druhá mocnina#8
sqrt(x)
x ** 2
@arcus tangens y / x#9
atan2(y, x)
@sinus/konsinus/tangens/cotangens#10
sin(x)
cos(x)
sin(x) / cos(x)
cos(x) / sin(x)
@přirozený logaritmus/e na x-tou#11
log(x)
exp(x)

3/8 Speciální proměnné

@řetězec vkládaný funkcí „print“ mezi argumenty/za poslední argument#1 (20)
$OFS⊨ undef
$ORS⊨ undef
@vstupní ukončovač záznamu#2 (21)
$RS⊨ "\n"
@verze Perlu (jen čtení)#3
$PERL_VERSION⊨ "v5.30.0"
@pole parametrů skriptu (obecně/příklad použití)#4 (22)
@ARGV
my $parametr1 = $ARGV[0];
@pole proměnných prostředí (obecně/příklad použití)#5 (23)
%ENV
$ENV{"HOME"}⊨ "/home/petr"
@PID/PPID procesu (jen čtení)#6
$PID⊨ 4485
getppid()⊨ 3010
@návratová hodnota procesu (jen čtení)#7 (24)
$CHILD_ERROR >> 8
@Označení souboru se zdrojovým kódem (jen čtení)#8 (25)
__FILE__⊨ "soubor.pl"
@Číslo řádky ve zdrojovém kódu (jen čtení)#9
__LINE__⊨ 351
@UID uživatele (jen čtení)#10
$UID⊨ 1000
@časová známka okamžiku spuštění skriptu (jen čtení)#11
$BASETIME⊨ 1605871925

4. Zaklínadla: Řízení toku

4/1 Podmínky

@provést blok příkazů, je-li podmínka pravdivá/nepravdivá#1
if (podmínka) { [příkazy] } [elsif (další podmínka) { [příkazy] }] [else { [příkazy] }]
unless (podmínka) { [příkazy] } [elsif (další podmínka) { [příkazy] }] [else { [příkazy] }]
@provést příkaz, je-li podmínka pravdivá (alterantivy)#2
podmínka and příkaz;
příkaz if (podmínka);
@provést příkaz, je-li podmínka nepravdivá (alterantivy)#3
podmínka or příkaz;
příkaz unless (podmínka);

4/2 Cykly

@cyklus for (s definicí vlastní proměnné/obecný)#1
[návěští:] for (my $identifikátor = výraz; [podmínka]; [výraz-iterace]) { [příkazy] }
[návěští:] for ([výraz-inicializace]; [podmínka]; [výraz-iterace]) { [příkazy] }
@cyklus foreach (obecně/příklady)#2
[návěští:] foreach [my] $identifikátor (seznam) { [příkazy] } [continue { [další příkazy] }]
foreach my $x (1, 2, 3) { printf("Číslo %d.\n", $x); }
foreach my $x (@ARG) { printf("%s\n", $x); }
@cyklus typu while (s pozitivní podmínkou/negovanou podmínkou)#3
[návěští:] while (podmínka) { [příkazy] } [continue { [další příkazy] }]
[návěští:] until (podmínka) { [příkazy] } [continue { [další příkazy] }]
@cyklus s podmínkou uprostřed#4
[návěští:] {
[příkazy]
last [návěští] unless (podmínka pokračování);
[příkazy]
redo;
}
@cyklus typu do...while (s pozitivní podmínkou/negovanou podmínkou)#5
do { [příkazy] } while (podmínka);
do { [příkazy] } while (!(podmínka));
@nekonečný cyklus#6
[návěští:] {
[příkazy]
redo;
}

4/3 Skoky

Poznámka k příkazům „last“, „next“ a „redo“: neoznačený blok příkazů „{}“ se v Perlu považuje za cyklus a tyto příkazy se na něj vztahují!

@vyskočit z funkce a vrátit návratovou hodnotu#1 (26)
return návratová hodnota;
@vyskočit za konec cyklu#2
last [návěští];
@ukončit program#3
exit([návratový-kód]);
@ukončit program s hlášením kritické chyby v tomto místě/ve volající funkci#4
die("text");
croak("text");
@skočit těsně před uzavírací závorku cyklu#5
next [návěští];
@pozdržet program o daný počet sekund#6
my $pomocnáProměnná = N;
while (($pomocnáProměnná -= sleep($pomocnáProměnná)) > 0) {}
@skočit přímo za otevírací závorku cyklu#7
redo [návěští];
@skočit na návěští (goto)(pevně dané/dynamicky určené)#8
goto návěští;
goto skalární_výraz;
@návěští pro příkaz goto#9 (27)
identifikátor: návěštím označený příkaz

4/4 Přepínač typu switch

Poznámka: Perl nenabízí žádnou konstrukci, která by fungovala jako plnohodnotný přepínač s propadáním přes větve, použitím jedné větve pro více hodnot a větví „default“ a vynucovala konstantnost a jedinečnost hodnot pro jednotlivé větve. Nabízí sice několik možností, jak dosáhnout stejného chování, ale všechny kromě asociativního pole ukazatelů na funkce se vnitřně chovají jako sekvence if-else-if. Většina použití příkazu „switch“ však může být rozumně nahrazena inteligentním použitím asociativních polí.

@přepínač bez propadání (řetězcové porovnání)#1
my %switch;
[$switch{hodnota} = sub {kód};]
[$switch{hodnota} = $switch{dříve-definovaná-hodnota};]
my $default = sub {blok-default};
{
my $switch = testovaný výraz;
($switch{$switch} // $default)->($switch);
}
@příklad použití#2
my $stdin = \*STDIN;
my $s = scalar(readline($stdin));
chomp($s);
my %switch;
$switch{"abc"} = sub {printf("Bylo ABC.\n")};
$switch{"xyz"} = sub {printf("Bylo XYZ.\n")};
$switch{"ABC"} = $switch{"abc"};
$switch{"XYZ"} = $switch{"xyz"};
my $default = sub {printf("Nebylo nic z toho.\n")};
{
my $switch = $s;
($switch{$switch} // $default)->($switch);
}

5. Zaklínadla: Řetězce a regulární výrazy

5/1 Základní operace

@spojit řetězce/pole na řetězec#1
$řetězec . $další_řetězec [. $ještě_další_řetězec]
join("[oddělovač]", pole-a-seznamy)
@zjistit délku řetězce ve znacích#2
length($skalár)⊨ 12
@jsou/nejsou si řetězce rovny?#3
řetězec1 eq řetězec2
řetězec1 ne řetězec2
@formátovat parametry na řetězec funkcí sprintf()#4
sprintf(formát, seznam, parametrů)
@jsou si řetězce rovny až na velikost písmen?#5
fc(řetězec1) eq fc(řetězec2)
@kódové číslo Unicode prvního/N-tého znaku řetězce#6
ord(řetězec)⊨ 382
ord(substr(řetězec, N-1, 1))
@zopakovat řetězec (obecně/příklad)#7
řetězec x počet
"abc" x 3⊨ "abcabcabc"
@řetězec na malá/velká písmena#8
lc(řetězec)⊨ "žluťoučký kůň"
uc(řetězec)⊨ "ŽLUŤOUČKÝ KŮŇ"
@obrátit pořadí znaků v řetězci#9
scalar(reverse(řetězec))⊨ adeceba
@zjistit počet bajtů po zakódování do UTF-8#10
^use Encode;
length(Encode::encode("UTF-8", řetězec))

5/2 Dělení na podřetězce

@získat podřetězec (obecně/max. délka zleva/max. délka zprava)#1 (28)
substr(řetězec, počáteční-index[, maximální-délka])
substr(řetězec, 0, maximální-délka)
maximální-délka > 0 ? substr(řetězec, -maximální-délka) : ""
@odebrat z proměnné ukončovač záznamu#2 (29)
chomp($proměnná);
@rozdělit řetězec na pole (obecně/příklady)#3 (30)
[@pole =] split(/reg-výraz-oddělovač/, dělený-řetězec[, maximální-počet-dílů])
@pole = split(/:/, $s);
@pole = split(/[:;]/, $s);
my $odd = "@*\\"; @pole = split(/\Q${odd}\E/, $s);
@vyjmout z řetězce v proměnné poslední znak (obecně/příklad)#4 (31)
chop($proměnná)
my $x = "abe"; printf("1: %s ", chop($x)); printf("2: %s\n", chop($x));⊨ 1: e 2: b
@rozdělit řetězec na poloviny#5
(substr($skalár, 0, length($skalár) / 2), substr($skalár, length($skalár) / 2))
@rozdělit řetězec na pole jednotlivých znaků#6
[@pole =] split("", řetězec)

5/3 Literály řetězců

@řetězcový literál (alternativy)#1 (32)
"text"
'text'
@řetězec: dvojitá uvozovka, tabulátor a \n#2
"...\"\t\n..."
@nulový bajt#3 (33)
"...\x{0}..."
@znak Unicode podle kódového čísla (obecně/příklady)#4
"...\x{hexčíslo}..."
"\x{017e}"⊨ "ž"
"\x{1f642}"
@prázdný řetězec#5
""
@získat ukazatel na skalární objekt (obecně/příklad)#6
\(řetězec)
my $ukazatel = \("Hello, world.\n");
@interpolovat skalární proměnnou#7
"...${identifikátor}..."
@interpolovat prvky pole#8 (34)
[[local] $LIST_SEPARATOR = "oddělovač";]
"...@{identifikátor}..."

5/4 Literály regulárních výrazů

@získat ukazatel na regulární výraz#1
qr/regulární výraz/[příznaky]
@regulární výraz přímo (jen v určitých kontextech)#2
/regulární výraz/
@interpolovat do regulárního výrazu: dynamický regulární výraz/doslovný řetězec/reg. výraz z ukazatele#3
qr/...${identifikátor_skalární_proměnné}.../
qr/...\Q${identifikátor_skalární_proměnné}\E.../
qr/...${identifikátor_skalární_proměnné}.../

5/5 Najít (regulární výrazy a podřetězce)

Poznámka: funkce next_match_*() hledají shodu s regulárním výrazem v podřetězci vymezeném parametry „počáteční-index“ a „délka-hledání“ (jsou-li zadány); všechny indexy vracené těmito funkcemi jsou ale platné v původním prohledávaném řetězci. Pokud další shodu nenajdou, vrátí místo každého indexu či délky nehodnotu undef.

@má/nemá shodu s regulárním výrazem?#1
řetězec =~ /regulární výraz/[i][m]
řetězec !~ /regulární výraz/[i][m]
@index začátku prvního/posledního výskytu podřetězce#2 (35)
index(řetězec, podřetězec [,index-začátku-vyhledávání])
rindex(řetězec, podřetězec [,limit])
@najít následující shodu s regulárním výrazem (ze shody vrátit: začátek a délku/index začátku/index za koncem/text/délku)#3 (36)
[($začátek, $délka) =] next_match(řetězec, qr/regulární výraz/[, počáteční-index[, délka-hledání]])
next_match_begin(řetězec, qr/regulární výraz/[, počáteční-index[, délka-hledání]])
next_match_end(řetězec, qr/regulární výraz/[, počáteční-index[, délka-hledání]])
next_match_text(řetězec, qr/regulární výraz/[, počáteční-index[, délka-hledání]])
next_match_length(řetězec, qr/regulární výraz/[, počáteční-index[, délka-hledání]])
@získat číslované záchyty následující shody s regulárním výrazem#4 (37)
[@pole =] next_match_captures(řetězec, qr/regulární výraz/[, počáteční-index[, délka-hledání]])
@počet shod#5
alength(matches(řetězec, qr/regulární výraz/[, počáteční-index[, délka-hledání]]))⊨ 0
@najít pole všech shod s regulárním výrazem#6 (38)
[@pole =] matches(řetězec, qr/regulární výraz/[, počáteční-index[, délka-hledání]])
@příklad: vypsat všechny shody v řetězci#7
my $řetězec = "abcxyzabcxyz-axc";
my $i = 0;
my @x;
while (defined((@x = next_match($řetězec, qr/a.c/, $i))[0])) {
printf("(%d, %d) = \"%s\"\n", @x, substr($řetězec, $x[0], $x[1]));
$i = $x[0] + max(1, $x[1]);
}
@odzvláštnit řetězec pro použití v dynamickém regulárním výrazu#8 (39)
quotemeta(řetězec)

5/6 Najít a nahradit v řetězcové proměnné

@provést náhradu pomocí regulárního výrazu (výsledek: přiřadit zpět/vrátit jako hodnotu)#1 (40)
$proměnná =~ s/regulární výraz/řetězec náhrady/[g][i][m][s];
$řetězec =~ s/regulární výraz/řetězec náhrady/r[g][i][m][s]
@nahradit všechny výskyty podřetězce v textu proměnné#2 (41)
[$proměnná_podřetězec = podřetězec;]
$proměnná =~ s/\Q${proměnná_podřetězec}\E/řetězec náhrady/g;
@přeložit znaky pomocí překladové tabulky#3 (42)
$proměnná =~ y/původní-znaky/nové-znaky/;
@nahradit podřetězec podle indexů (původní podřetězec zahodit/získat jako návr. hodnotu)#4
substr($proměnná, index[, max-délka]) = nový-podřetězec;
substr($proměnná, index, max-délka, nový-podřetězec)

5/7 Konverze čísel na řetězce a naopak

@hexadecimální/desítkový/oktalový řetězec na číslo#1
hex(řetězec)⊨ 1015
řetězec + 0⊨ 1015
oct(řetězec)⊨ 1015
@celé číslo na hexadecimální řetězec s malými/velkými písmeny#2
sprintf("%x", číslo)⊨ "3f7"
sprintf("%X", číslo)⊨ "3F7"
@celé číslo na oktalový řetězec#3
sprintf("%o", číslo)⊨ "1767"

5/8 Heše

@získat číselnou heš řetězce#1
^use Digest::MD5;
^use Encode;
unpack("L", substr(Digest::MD5::md5(Encode::encode("UTF-8", řetězec)), 0, 4))⊨ "1834341228"
@MD5 heš řetězce bajtů#2
^use Digest::MD5;
Digest::MD5::md5_hex(řetězec-bajtů)⊨ "6cd3556deb0da54bca060b4c39479839"
@SHA256 heš řetězce bajtů#3
^use Digest::SHA;
Digest::SHA::sha256_hex(řetězec-bajtů)⊨ "315f5bdb76d078c43b8ac0064e4a0164612b1f (...)"
@SHA1 heš řetězce bajtů#4
^use Digest::SHA;
Digest::SHA::sha1_hex(řetězec-bajtů)⊨ "943a702d06f34599aee1f8da8ef9f7296031d699"
@SHA512 heš řetězce bajtů#5
^use Digest::SHA;
Digest::SHA::sha512_hex(řetězec-bajtů)⊨ "c1527cd893c124773d811911970c8fe6e857d6 (...)"

6. Zaklínadla: Pole

6/1 Literály (vytvořit pole z prvků)

@seznam (obecně/příkady)#1 (43)
([prvek seznamu[, další prvek seznamu]])
(1, "", undef)
(1 + 1, (2 + 2, 3 + 3), array("", undef, ""))
@seznam ze slov (alternativy)#2 (44)
qw(slova)
qw{slova}
@získat ukazatel na anonymní pole#3
[[prvek seznamu[, další prvek seznamu]]]
@seznam celých čísel v daném rozsahu (obecně/příklady)#4
(celé-číslo..celé-číslo)
(-1..4)⊨ (-1, 0, 1, 2, 3, 4)
(2..5, -3..-1)⊨ (2, 3, 4, 5, -3, -2, -1)
@zopakovat seznam (obecně/příklad použití)#5
(seznam) x počet
my @dvanáct_undefů = (undef) x 12;
@přečíst konstantu typu seznam (obecně)#6
(identifikátor)
@přečíst konstantu typu seznam (příklad)#7
use constant můjseznam => (1, 2, 3, 4);
my @mojepole = (-1, 0, (můjseznam), 5, 6);
@seznam znaků UCS v daném kódovém rozsahu (alternativy)#8
(map {chr($ARG)} první-kód..poslední-kód)
(map {chr($ARG)} ord("první-znak")..ord("poslední-znak"))

6/2 Základní operace

@zjistit počet prvků pole#1
alength(@pole)
@přečíst prvek pole (obecně/příklady)#2 (45)
$identifikátor_pole[index]
$mojepole[12]
my $prvek = (získej_pole(1))[$i];
@přiřadit prvku pole (obecně/příklad)#3
$identifikátor_pole[index] = skalár
$mojepole[12] = undef
@přiřadit celé pole (alternativy)#4
@cílové_pole = @zdrojové_pole
@cílové_pole = (seznam)
@rozložit pole do nových skalárních proměnných#5 (46)
my ($id[, $další_id]) = @pole;
@je pole prázdné?#6
alength(@pole) == 0
@zjistit typy prvků pole#7 (47)
typy(@pole)⊨ "ssuRuA"
@zopakovat seznam či obsah pole (obecně/příklady)#8
seznam x počet
("a", undef) x 2⊨ ("a", undef, "a", undef)
(@test) x 5
@první/poslední prvek pole#9
$identifikátor_pole[0]
$identifikátor_pole[-1]

6/3 Vkládání/vyjímání prvků

@vyjmout první/poslední/určitý prvek pole#1 (48)
shift(@pole)
pop(@pole)
splice(@pole, index, 1);
@vložit prvek na začátek pole/konec pole/určitý index#2 (49)
unshift(@pole, skalár);
push(@pole, skalár);
splice(@pole, index, 0, skalár);
@smazat všechny prvky/úsek#3
@pole = ();
splice(@pole, první-smaz-index, počet-ke-smazání);

6/4 Filtrování

@vybrat prvky podle indexu (obecně/příklady)#1
@pole[seznam, indexů]
my @x = (array(0, 10, 20, 30, 40, 50))[1..3];⊨ (10, 20, 30)
my @x = (array(0, 10, 20, 30, 40, 50))[3, 2, 3];⊨ (30, 20, 30)
my @a = @pole_prvků[@pole_indexů];
@vybrat prvky splňující podmínku#2 (50)
array(grep {
příkaz
} @pole)
@vybrat prvních/posledních N prvků#3 (51)
^use List::Util;
List::Util::head(N, seznam)
List::Util::tail(N, seznam)
@vybrat sudé/liché prvky z pole o sudém počtu prvků#4
^use List::Util;
List::Util::pairkeys(seznam)
List::Util::pairvalues(seznam)

6/5 Transformace a zpracování pole

@transformovat po prvcích#1 (52)
(map {
příkaz
} @pole)
@zpracovat pole po N-ticích (destruktivně)#2 (53)
while (alength(@pole) != 0) {
my @ntice = array(splice(@pole, 0, N));
zpracování
}
@sečíst/vynásobit prvky pole#3
^use List::Util;
List::Util::sum0(seznam)
List::Util::product(seznam)
@příklad: ze seznamu celých čísel sudá čísla zdvojit a lichá vynechat#4
my @čísla = (1, 2, 3, 14, 15);
@čísla = (map {$ARG % 2 == 0 ? ($ARG, $ARG) : ()} @čísla);⊨ (2, 2, 14, 14)
@vytvořit pole ukazatelů na pole dvojic ([a, b], [c, d], ...)#5 (54)
^use List::Util;
List::Util::pairs(seznam)

6/6 Řazení a přeskládání prvků v poli

Poznámka: volání funkce „sort“ nemůžete použít v kontextu, kde jsou viditelné vámi deklarované proměnné $a nebo $b. Proto se deklaraci takových proměnných vyhněte, nebo volání funkce „sort()“ odsuňte do samostatné funkce.

@seřadit řetězce podle aktuální lokalizace (vzestupně/sestupně)#1 (55)
[@pole =] do { use locale; array(sort {$a cmp $b} seznam); }
[@pole =] do { use locale; array(sort {$b cmp $a} seznam); }
@seřadit řetězce podle kódové hodnoty znaků (vzestupně/sestupně)#2
[@pole =] do { no locale; array(sort {$a cmp $b} seznam); }
[@pole =] do { no locale; array(sort {$b cmp $a} seznam); }
@obrátit pořadí#3
array(reverse(seznam))
@náhodně přeskládat#4
^use List::Util;
[@pole =] List::Util::shuffle(@pole)
@seřadit čísla (vzestupně/sestupně)#5 (56)
[@pole =] array(sort {$a <=> $b} seznam)
[@pole =] array(sort {$b <=> $a} seznam)
@seřadit podle uživatelské porovnávací funkce#6 (57)
[@pole =] array(sort {
příkaz
} seznam)
@seřadit řetězce podle jednotných pravidel Unicode vzestupně (velikost písmen nerozlišovat)#7 (58)
^use Unicode::Collate;
^my $porovnávač = Unicode::Collate->new("level", úroveň-řazení);
[@pole =] array(sort {$porovnávač->cmp($a, $b)} seznam)

6/7 Vyhledávání a testování

@najít první prvek vyhovující podmínce (hodnotu/index)#1 (59)
^use List::Util;
(List::Util::first { podmínka } seznam)
(List::Util::first { podmínka } 0..(alength(@pole) - 1))
@najít minimální/maximální číselnou hodnotu#2
^use List::Util;
List::Util::min(seznam)
List::Util::max(seznam)

7. Zaklínadla: Asociativní pole

7/1 Jako celek

@literál asociativního pole (jako seznam/jako ukazatel na asociativní pole)#1
([klíč, hodnota[, další klíč, další hodnota]])
{[klíč, hodnota[, další klíč, další hodnota]]}
@získat počet dvojic v asociativním poli#2
alength(keys(%pole))⊨ 3
@získat pole klíčů/hodnot#3 (60)
keys(%pole)⊨ (1, 2, 3)
values(%pole)⊨ ("", undef, "xyz")
@transpozice (klíče na hodnoty a hodnoty na klíče)#4

7/2 Prvky

@přečíst prvek asociativního pole/přiřadit do něj/příklad#1 (61)
$identifikátor{klíč}
$identifikátor{klíč} = hodnota
$apole{"abc"} = "def";
@smazat prvek/všechny prvky#2 (62)
delete $id_pole{klíč};
%pole = ();
@obsahuje prvek?#3
exists($identifikátor{klíč})
@přidat či přepsat prvek#4
$identifikátor{klíč} = hodnota
@přiřadit hodnoty více prvkům najednou (obecně/příklady)#5
@identifikátor{seznam, klíčů} = (seznam, hodnot);
@apole{"a", "b"} = ("A", "B");
@apole{@klíče} = @hodnoty;
@apole{@klíče} = ("xyz") x alength(@klíče);
@smazat prvky splňující podmínku#6
@vytvořit pole výběrem prvků z asoc. pole (přímo/přes ukazatel)#7
[@pole =] @identifikátor{seznam, klíčů}
@smazat více prvků najednou (přímo/přes ukazatel)#8
delete @identifikátor{seznam, klíčů};
@smazat prvek přes ukazatel na asociativní pole#9
delete $ukazatel->{klíč};

8. Zaklínadla: Ukazatelé

8/1 Ukazatelé obecně

@je skalár ukazatel?#1
defined(ref($skalár))
@zjistit typ odkazovaného objektu (alternativy)#2 (63)
typy($skalár)
ref($skalár)
@odkazují dva ukazatelé na tentýž objekt?#3
^use Scalar::Util;
Scalar::Util::refaddr($a) == Scalar::Util::refaddr($b)

8/2 Získat ukazatel

@získat ukazatel na proměnnou: skalár/pole/asociativní pole#1
\$identifkátor_skalární_proměnné
\@identifkátor_pole
\%identifkátor_asociativního_pole
@získat ukazatel na pojmenovanou funkci/anonymní funkci#2 (64)
\&identifkátor_funkce
sub {[příkazy]}
@získat ukazatel na regulární výraz (obecně/příklad)#3
qr/regulární výraz/
$můjVýraz = qr/^ab\.c/
@získat ukazatel na prvek pole/hodnotu v asociativním poli#4 (65)
\$identifkátor_pole[index]
\$identifkátor_asociativního_pole{klíč}
@získat ukazatel na anonymní objekt: skalár/pole/asociativní pole#5
\(hodnota-nebo-undef)
[seznam]
{seznam,dvojic}
@získat ukazatel na hodnotu v asociativním poli dostupném přes ukazatel#6
\$ukazatel-na-asoc-pole->{klíč}

8/3 Dereferencovat ukazatel

@přistoupit přes ukazatel ke skaláru/poli/asociativnímu poli/funkci#1 (66)
${$identifikátor_ukazatele}
@{$identifikátor_ukazatele}
%{$identifikátor_ukazatele}
&{$identifikátor_ukazatele}
@zavolat přes ukazatel funkci#2
$ukazatel->(seznam, parametrů)
@přistoupit k prvku pole/asociativního pole dostupného přes ukazatel#3
$ukazatel->[index]
$ukazatel->{klíč}

8/4 Slabé ukazatele

@změnit ukazatel na slabý#1
^use Scalar::Util;
Scalar::Util::weaken($ukazatel);
@je ukazatel slabý?#2
^use Scalar::Util;
Scalar::Util::isweak($ukazatel)
@změnit slabý ukazatel zpět na silný#3
^use Scalar::Util;
Scalar::Util::unweaken($ukazatel);

9. Zaklínadla: Vstup/výstup

9/1 Otevřít/zavřít

@zavřít proud#1
close($proud) [or die(zpráva)];
@získat standardní vstup/standardní výstup/standardní chybový výstup#2
my $proud = \*STDIN; [binmode($proud, ":raw");]
my $proud = \*STDOUT; [binmode($proud, ":raw");]
my $proud = \*STDERR; [binmode($proud, ":raw");]
@otevřít soubor jako textový (normálně/se striktními kontrolami)#3 (67)
open(my $proud, "režim:utf8", "cesta/k/souboru") [or die("chybová zpráva")];
open(my $proud, "režim:encoding(UTF-8)", "cesta/k/souboru") [or die("chybová zpráva")];
@otevřít soubor jako binární#4 (68)
open(my $proud, "režim:raw", "cesta/k/souboru") [or die("chybová zpráva")];
@otevřít rouru pro zápis/pro čtení#5
open(my $proud, "|-", "název-příkazu"[, parametr-příkazu]) [or die(zpráva)]; [binmode($proud, ":raw");]
open(my $proud, "-|", "název-příkazu"[, parametr-příkazu]) [or die(zpráva)]; [binmode($proud, ":raw");]
@otevřít číslovaný vstup či výstup#6 (69)
open(my $proud, "režim&=číslo") [or die("chybová zpráva")]; [binmode($proud, ":raw");]
@přepnout režim proudu na binární/textový#7 (70)
binmode($proud, ":raw");
binmode($proud, ":utf8");

9/2 Standardní výstup a chybová hlášení

@vypsat položky seznamu oddělené hodnotou $OFS a zakončené hodnotou $ORS#1
print(položky, seznamu);
@printf()#2
printf("formátovací řetězec"[, parametry]);
@vypsat řetězec#3
printf("%s", výraz-typu-řetězec);
@vypsat datovou strukturu pro člověka (zejména pro účely ladění)#4
^use Data::Dumper;
printf("%s", Dumper(seznam));
@vypsat varování ohedně tohoto místa/místa ve volající funkci na standardní chybový výstup#5 (71)
warn("zpráva");
carp("zpráva");

9/3 Čtení (vstup) v textovém režimu

@načíst řádek bez ukončovače#1 (72)
$cíl = scalar(readline($proud));
chomp($cíl) if (defined($cíl));
@načíst všechny zbývající řádky bez ukončovačů do pole#2
@cíl = array(readline($f));
chomp(@cíl);
@načíst N znaků (N≥1)/1 znak#3 (73)
$cíl = do {local $RS = \(N); scalar(readline($proud));}
$cíl = getc($proud);
@načíst celý zbytek souboru do řetězce#4
$cíl = do {local $RS = undef; scalar(readline($proud));}
@načíst řádku/všechny zbývající řádky s ukončovačem#5
$cíl = scalar(readline($proud));
@cíl = array(readline($f));
@načíst a zahodit všechny zbývající řádky#6
while (defined(scalar(readline($proud)))) {}

9/4 Zápis (výstup) v textovém režimu

@vypsat položky seznamu oddělené hodnotou $OFS a zakončené hodnotou $ORS#1
fprint($proud, položky, seznamu);
@printf()#2
fprintf($proud, "formátovací řetězec"[, parametry]);
@vypsat řetězec#3
fprintf($proud, "%s", řetězec);

9/5 Čtení (vstup) v binárním režimu

@načíst pevný maximální počet bajtů#1
read($proud, $proměnná-cíl, max-bajtů[, počáteční-index-do-cíle])
@načíst jeden bajt#2
$cíl = getc($proud);
@načíst celý zbytek souboru do řetězce bajtů#3
$cíl = do {local $RS = undef; scalar(readline($proud));}
@konvertovat bajty z řetězce na pole číselných hodnot#4
@cíl = unpack("C*", $řetězec);

9/6 Zápis a ostatní operace v binárním režimu

@zapsat bajty (z řetězce bajtů/z pole čísel)#1
fprintf($proud, "%s", řetězec);
fprintf($proud, "%s", pack("C*", řetězec));
@zapsat bajt (znak/z číselné hodnoty)#2
fprintf($proud, "%s", $znak);
fprintf($proud, "%c", $číslo);
@přesun na pozici N bajtů od začátku/od konce/od akt. pozice vpřed/od akt. poz. vzad (nepoužívat na roury)#3
seek($f, N, 0);
seek($f, -N, 2);
seek($f, N, 1);
seek($f, -N, 1);
@zjistit pozici v bajtech od začátku souboru (nepoužívat na roury)#4
tell($f)⊨ 737
@zkrátit soubor otevřený pro zápis (nepoužívat na roury)#5
truncate($proud, délka-v-bajtech) [&& seek($f, nová-pozice, odkud)]

9/7 Operace se soubory a pevnými a symbolickými odkazy

@nastavit mód (přístupová práva)(obecně/příklad)#1 (74)
chmod(číslo, cesta);
chmod(04777, "../a.txt", "b.txt");
@přejmenovat soubor#2
rename("původní název", "nový název") [or die("chybové hlášení")];
@vytvořit pevný odkaz na soubor#3
link("$původní/cesta", "nová/cesta") [or die("chybové hlášení")];
@vytvořit symbolický odkaz (obecně/příklad)#4
symlink("obsah odkazu", "cesta/k/odkazu") [or die("chybové hlášení")];
@odstranit soubor či symbolický odkaz#5
unlink(cesta) [or zpracovat chybu]

9/8 Operace s adresáři

@získat pole názvů položek v adresáři#1 (75)
if (opendir(my $identifikátor, $cesta)) {
@pole = array(readdir($identifikátor));
closedir($identifikátor);
}
@změnit aktuální adresář#2
chdir(cesta) [or die(...)];
@zjistit aktuální adresář#3
^use Cwd;
getcwd()⊨ "/home/alena/linux-spellbook"
@vytvořit adresář#4
mkdir($cesta) [or zpracovat chybu]
@odstranit prázdný adresář#5
rmdir($cesta) [or zpracovat chybu]
@přejmenovat adresář#6
rename("původní název", "nový název") [or die("chybové hlášení")];

9/9 Zjistit informace o adresářové položce

Poznámka: v případě, že funkce stat() selže, vrátí prázné pole; proto čtení jeho kteréhokoliv prvku vrátí undef. Mód a typ adresářové položky budou v takovém případě 0.

@typ adresářové položky (s následováním symb. odkazů/bez následování)#1 (76)
((stat("cesta"))[2] // 0) >> 12⊨ 8
((lstat("cesta"))[2] // 0) >> 12⊨ 10
@velikost v bajtech#2
(stat("cesta"))[7]⊨ 15543
@čas změněno/čteno#3 (77)
(stat("cesta"))[9]⊨ 1607766627
(stat("cesta"))[8]⊨ 1607766627
@mód#4 (78)
(stat("cesta"))[2] // 0 & 07777⊨ 436
@vlastník/skupina (obojí číselně)#5
(stat("cesta"))[4]⊨ 1000
(stat("cesta"))[5]⊨ 1000
@počet pevných odkazů#6
(stat("cesta"))[3]⊨ 1
@číslo zařízení/i-uzlu#7
(stat("cesta"))[0]⊨ 47
(stat("cesta"))[1]⊨ 4

10. Parametry příkazů

lkk perl [parametry Perlu] soubor-skriptu.pl [parametry skriptu]
lkk perl -ne 'skript'
'-Mkód'Na začátek hlavního skriptu před čtením vloží příkaz „use kód;“ Toho je možné využít k připojení modulů, importu identifikátorů z nich, nastavení direktiv apod. Lze použít opakovaně.
○ -0 ○ -0777 ◉ -0x0A ○ -0x017DNastavit $RS na: "\x{0}"/undef (celý soubor jako jeden záznam)/"\n"/"Ž" (uvádí se kód hexadecimálně).
☐ -C0Vypne implicitní podporu Unicode. (Zatím jsem nezkoušel/a.)
○ -n ○ -pRežim připomínající GNU awk. Parametry skriptu jsou interpretovány jako cesty k souborům, které mají být čteny. Celý program se pak obalí do implictní smyčky, která z těchto souborů načítá záznamy ukončené $RS do proměnné $ARG. (Na rozdíl od GNU awk ukončovač záznamu není odebrán, k tomu je potřeba použít „chomp($ARG);“.) Hodnota $ARG se na konci každého cyklu: zahodí/vypíše. Tyto volby se obvykle používají v kombinaci s volbou -e, u delšího skriptu je totiž výhodnější čtecí cyklus napsat ručně.
☐ -e 'skript'Uvede skript na příkazové řádce namísto jeho čtení ze souboru.
-I cestaVloží uvedenou cestu na začátek seznamu adresářů pro vyhledávání modulů (ekvivalent příkazu „use lib“ nebo parametru „'-Mlib("cesta")'“). Lze použít opakovaně. Seznam se prohledává od začátku, takže nově vložená cesta bude mít přednost před všemi předchozími.

Varování: Nikdy do svých skriptů Perlu neuvádějte direktivu interpretu „#!“ (např. „#!/usr/bin/perl“)! Není snadné to udělat správně a neopatrné použití této direktivy může způsobit, že skript nepůjde spustit vůbec nebo se místo něj spustí něco úplně jiného.

11. Instalace na Ubuntu

Všechny použité nástroje jsou základními součástmi Ubuntu přítomnými i v minimální instalaci (jen balíček Linuxu: Knihy kouzel si musíte nainstalovat, aby vám fungoval spouštěč „lkk“ a aby byl dostupný modul LinuxKnihaKouzel.pm).

12. Ukázka

@Ukázka 1: Zpracování binárního souboru #1
use Digest::MD5;
use constant konec_řádku => "\n";
my $vstup = \*STDIN; # standardní vstup
binmode($vstup, ":raw"); # binární režim
$RS = "\x{0}"; $ORS = (konec_řádku); # speciální proměnné
my $s;
while (defined($s = scalar(readline($vstup)))) {
chomp($s); # zahodit ukončovač \0
print(Digest::MD5::md5_hex($s));
}
@Ukázka 2: Zpracování textového souboru#2
my $vstup = \*STDIN;
my @řádky = array(readline($vstup)); # všechny řádky najednou
chomp(@řádky);
printf("Na vstupu je %d řádků.\n", alength(@řádky));
my ($původní, $nový) = ('.**$x@y%z', '&z$y.*@x');
for my $i (0..(alength(@řádky) - 1)) {
$řádky[$i] =~ s/\Q${původní}\E/($&)=> ${nový}/g;
}
print("<", join(">\n<", @řádky), ">\n");

13. Tipy a zkušenosti

  • Autovivifikace: Operátory („->[]“ a „->{}“) lze bezpečně použít i v případech, kdy na jejich levé straně stojí neexistující prvek asociativního pole či pole nebo neinicializovaná proměnná. Perl totiž hodnotu na levé straně zkontroluje, a pokud je undef, automaticky tam přiřadí ukazatel na nové, prázdné pole (resp. asociativní pole). Tato funkce se nazývá autovivifikace a výrazně usnadňuje práci s vnořenými asociativními poli. Dejte si ale pozor na skutečnost, že k ní dojde při každé dereferenci, nejen při takové, do které pak přiřazujete! To znamená, že i příkaz „delete $p->{"x"}“ způsobí, že se do $p (pokud je undef) přiřadí ukazatel na prázdné asociativní pole.
  • Předávání parametrů do funkcí: Přiřaditelné skaláry se do funkcí předávají vždy odkazem; přiřazením do prvků zvláštního pole „@ARG“ lze přiřadit do skalárních proměnných, které byly předány funkci jako parametry. Pole se při předávání do funkce (pokud tomu nebrání její prototyp) rozloží na všechny svoje prvky v náležitém pořadí a ty se předají odkazem. Asociativní pole se rozloží na posloupnost dvojic „klíč,hodnota“, příčemž klíče se předají hodnotou (jsou nepřiřaditelné), zatímco hodnoty se předají odkazem. Perl neprovádí žádnou automatickou kontrolu počtu, typu či hodnoty předaných parametrů; ta je výhradně zodpovědností volané funkce. Je výhodné při ní použít funkci „typy()“ a regulární výraz.
  • Vnořené datové struktury: Vnořené datové struktury se v Perlu realizují téměř výhradně pomocí ukazatelů. Příklad: my @vnořená_pole = ([1, 2], [3, 4]);
  • print() a printf(): Dokumentace Perlu radí upřednostňovat funkci „print“ před „printf“, protože je rychlejší a snáze se píše. To první je nejspíš pravda, ale pokud ji chcete použít korektně, musíte mít kontrolu nad hodnotami globálních proměnných $OFS a $ORS, protože funkce „print“ je vypisuje, a budou-li nastaveny na nečekané hodnoty z jiné části programu, bude výstup vaší funkce nekorektní. Napsat "%s" do printf je obvykle mnohem jednodušší než neustále přiřazovat $OFS a $ORS.
  • Funkce map(): Návratovou hodnotou posledního příkazu v bloku funkce „map()“ nemusí být skalár; může to být i seznam či pole. V takovém případě se jeho obsah do výsledného pole zploští, díky čemuž nemusí funkce map() vrátit stejný počet prvků jako obržela; může jich být víc i méně.
  • Blok kódu: Blok kódu předávaný funkci jako zvláštní první parametr (což se týká především vestavěných funkcí grep(), map() a sort() nesmí obsahovat příkaz „return“, jinak tento příkaz ukončí obalující funkci a vrátí návratovou hodnotu z ní! To neplatí v případě, kdy se blok předává ukazatelem na anonymní funkci (s klíčovým slovem „sub“), tam je naopak příkaz „return“ vhodný.
  • Správa paměti a slabé ukazatele: Správa paměti v Perlu je založená na počítání odkazů. Jakýkoliv objekt bude zrušen (včetně případného volání destruktoru) v momentě, kdy počítadlo odkazů na něj klesne na nulu. Slabí ukazatelé se do počtu odkazů nepočítají, a pokud bude objekt zrušen v době jejich existence, automaticky přitom získají nehodnotu undef. Podle dokumentace je slabost ukazatele typová vlastnost objektu, která se nekopíruje (jakákoliv kopie slabého ukazatele je opět silný odkaz) a přepíše se přiřazením, pokud nejde o přiřazení slabého ukazatele téže hodnoty.

13/1 Regulární výraz a řetězec náhrady

Uvnitř regulárních výrazů v Perlu můžete použít interpolaci skalární proměnné, např. takto:

if ("abc" =~ /a${proměnná}c/) {...}

Proměnná může obsahovat buď ukazatel na regulární výraz (ten se pak zakomponuje do nového regulárního výrazu), nebo textový řetězec – ten se za běhu interpretuje jako regulární výraz a také se zakomponuje.

Pokud proměnná obsahuje text a chcete ho vložit bez intepretace zvláštních znaků, použijte tento zvláštní druh interpolace do regulárního výrazu:

if ("abc" =~ /a\Q${proměnná}\Ec/) {...}

Uvnitř řetězců náhrady platí stejná pravidla odzvláštňování jako v řetězcových literálech obklopených dvojitými uvozovkami, až na to, že „"“ je obyčejný znak a „/“ je na místo toho zvláštní. Uvnitř řetězce náhrady můžete použít speciální proměnné $& (nahradí se za text shody) a $1, $2, ..., $9, ${10}, ... (nahradí se za text odpovídajícího záchytu). Také tam můžete použít interpolaci obyčejné proměnné, její text se použije doslova, bez interpretace zvláštních znaků.

14. Další zdroje informací

Poznámka č. 1: Pro spuštění příkazu „perldoc“ si musíte doinstalovat balíček „perl-doc“:

sudo apt-get install perl-doc

Poznámka č. 2: Webové tutorialy a oficiální dokumentace obsahují značné množství dalších konstrukcí, které v Linuxu: Knize kouzel nejsou zmíněny (např. operátor „<>“ nebo příkaz „given“). U řady z nich má jejich vynechání dobrý důvod a jejich použití může vést k nezamýšlenému chování programu, kterému budete moci porozumět jen po nastudování obrovského množství dokumentace v angličtině. Pokud se tomu chcete vyhnout, používejte jen jazykové konstrukce z kapitol Linuxu: Knihy kouzel.

15. Pomocné funkce a skripty

@lkk perl – spouštěč, který spustí skript Perlu s doporučenými parametry#1
#!/bin/bash
exec perl -CSDAL -I/usr/share/lkk/perl -Mv5.26.0 -Mstrict -Mwarnings -Mutf8 -MEnglish -MLinuxKnihaKouzel "$@"

16. Zákulisí kapitoly

V této verzi kapitoly chybí:

Tato kapitola záměrně nepokrývá:

  • nic
1 „Místní proměnná“ je viditelná v bloku, kde je deklarována. Inicializuje se při každém průchodu znovu a opuštěním bloku zaniká. Místní proměnná není nikdy viditelná z jiných zdrojových souborů.
2 „Trvanlivá proměnná“ je stejně jako místní proměnná viditelná v bloku (popř. zdrojovém souboru), kde je deklarována. Inicializuje se však pouze při prvním průchodu a trvá až do ukončení programu.
3 „Globální proměnná“ je viditelná v celém programu (ve všech zdrojových souborech, a to i v případě, že je deklarovaná uvnitř definice funkce), inicializuje se při prvním průchodu a trvá až do ukončení programu.
4 Poznámka: kvůli omezením Perlu je každá konstanta globální v rámci jmenného prostoru a viditelná i z ostatních zdrojových souborů. V její inicializaci může být obecný výraz, ale bude vyhodnocován v době překladu, takže je omezeno, co může obsahovat. Může však obsahovat již dříve definované konstanty.
5 Příkaz „local“ způsobí, že v paměti vznikne nový objekt příslušného typu a uvedená globální proměnná se na něj dočasně „přesměruje“, takže veškeré odkazy na danou globální proměnnou (i uvnitř volaných knihovních funkcí) budou přistupovat k novému objektu místo k tomu původnímu. Do původního stavu se proměnná vrátí po opuštění bloku kódu, v němž byla deklarací „local“ překryta.
6 Závorky kolem identifikátoru konstanty můžete vynechat tehdy, když je obalený jinými kulatými závorkami; nesmíte je vynechat v případě, že je obalený složenými či hranatými závorkami!
7 Vracené typy jsou: u = undef, s = číslo či řetězec, S = ukazatel na skalár, A = ukazatel na pole, H = ukazatel na asociativní pole, C = ukazatel na funkci („kód“), R = ukazatel na regulární výraz, F = ukazatel na vstupně/výstupní proud a "<Název::Třídy>" pro ukazatele na objekty tříd (dosadí se název třídy).
8 Operátor „//“ se vyhodnocuje postupně. To znamená, že pokud výraz na jeho levé straně není undef, výraz na pravé straně se již nevyhodnotí. To umožňuje ho využít v kombinaci např. s funkcí „die()“.
9 Poznámka: při volání uživatelské funkce se závorky interpretují jako seznam, proto v něm dochází ke zplošťování. Tomu lze zabránit pomocí tzv. prototypů, proto k němu u vestavěných a některých knihovních funkcí nedochází. To vám umožňuje např. funkci „push“ předat přímo pole, aniž by se zploštilo.
10 Pozor! Předávaný blok příkazů se chová jako samostatná funkce (dostává parametry v poli @ARG a vrací hodnotu), až na příkaz „return“. Ten v tomto bloku NIKDY nepoužívejte! Návratovou hodnotou bloku bude hodnota posledního provedeného příkazu. Pokud blok obsahuje jen jeden krátký příkaz, můžete volání zapsat na jednu řádku.
11 Tento příkaz předá řízení přímo na začátek uvedené funkce, jako by byla volána místo funkce právě prováděné. Všechny lokální proměnné jsou před voláním zrušeny a pole @ARG bude předáno tak, jak právě je (včetně případných změn, které v něm stávající funkce provedla).
12 Funkce nemusí být definovaná před prvním použitím, ale pokud má prototyp, ten musí být před prvním použitím znám.
13 Funkce definovaná s modifikátorem „lvalue“ musí vrátit přiřaditelný skalár (proměnnou, prvek pole či hodnotu v asociativním poli). Nemůže vracet pole, undef apod.
14 Na rozdíl od normálních polí, prvky tohoto speciálního pole se do funkce předávají odkazem. To znamená, že přímým přiřazením do prvků tohoto pole můžete změnit proměnné (popř. prvky pole či hodnoty asociativního pole), které byly při volání funkce zadány. Pokud bylo daným parametrem funkce něco nepřiřaditelného, takové přiřazení se bude tiše ignorovat.
15 Předaný blok zavoláte jako funkci příkazem „$id->(parametry)“, kde id je zvolený identifikátor proměnné. Parametry (volitelné) předané volání bloku jsou v definici předaného bloku přístupné v poli @ARG.
16 Pozor, před znakem „=“ na uvedených speciálních řádcích nesmí být žádný jiný znak, ani odsazení! Víceřádkové komentáře nelze zanořovat.
17 Část „>> 8“ je nutná v případě, kdy vás zajímá návratový kód procesu. Ten je totiž v návratové hodnotě funkce vynásoben hodnotou 256 (tedy bitově posunut o 8 bitů doleva). Poznámka: funkce „system()“ vám neumožňuje zapisovat na vstup procesu nebo číst z jeho výstupu. K těmto účelům použijte roury popsané v sekci „Zaklínadla: Vstup/výstup“.
18 Ohledně nastavení oddělovače — viz poznámku pod čarou týkající se speciální proměnné $RS.
19 Funkce „div“ (z balíčku LinuxKnihaKouzel.pl) provede celočíselné dělení absolutních hodnot zadaných čísel a vrací dvojici (výsledek, zbytek); výsledek z ní získáte přečtením prvku s indexem 0.
20 Výchozí hodnota obou proměnných je nehodnota undef, která zde má stejný význam jako prázdný řetězec.
21 Jako ukončovač lze nastavit libovolný řetězec. Existují dva zvláštní případy: nastavení na prázdný řetězec způsobí, že jako ukončovač bude rozpoznána jakákoliv posloupnost dvou nebo více znaků \n; nehodnota undef způsobí, že vstup nebude dělený na záznamy a rovnou se načte celý zbytek vstupního souboru.
22 Na rozdíl od Bashe toto pole neobsahuje nultý parametr (název skriptu). Jsou to opravdu jen parametry předané skriptu na příkazové řádce.
23 Přiřazením je možno proměnné prostředí vytvářet a měnit.
24 Podle dokumentace se hodnota této proměnné nastavuje při uzavření roury funkcí „close()“, při úspěšném ukončení funkcí „wait()“ a „waitpid()“ a při ukončení funkcí „readpipe()“ a „system()“.
25 Tato proměnná je určena především pro ladění; raději se příliš nespoléhejte na konkrétní tvar, který vám vrátí.
26 Příkaz „return“ v Perlu není povinný. Při jeho nepoužití vrátí Perl hodnotu posledního provedeného příkazu ve funkci.
27 Poznámka: jeden příkaz může být označen více návěštími.
28 Počáteční index může být i záporný; v takovém případě se k němu před použitím přičte délka řetězce. Výsledný interval daný počátečním indexem a maximální délkou se musí s pozicemi existujícími v řetězci alespoň dotýkat, pokud bude zcela mimo řetězec, funkce vypíše varování a vrátí undef. Maximální délka se vždy počítá od zadané pozice, ne od skutečného začátku řetězce, proto např. „substr("AB", -3, 2)“ vrátí pouze "A".
29 Odebere z konce řetězce v proměnné ukončovač podle nastavení speciální proměnné $RS. Velmi často se používá po načtení řádky. Pokud řetězec ukončovačem nekončí, proměnná zůstane nezměněná.
30 Pozor: pokud regulární výraz oddělovače obsahuje záchyty, příkaz „split“ pro každý záchyt vloží na dané místo výstupního pole navíc řetězec s textem záchytu; pokud daný záchyt nebyl použit, vloží se tam undef. Podrobnější vysvětlení v dokumentaci funkce „split“.
31 Pro prázdný řetězec vrací funkce chop() prázdný řetězec a proměnnou nezmění. Podle dokumentace funkce „chop()“ nevyžaduje okopírování celého řetězce, takže může být použita v cyklu pro zpracování řetězce znak po znaku.
32 Ve dvojitých uvozovkách jsou zvláštními znaky „\“, „$“, „@“ a „"“, všechny lze odzvláštnit zpětným lomítkem. Navíc se tam intepretují některé sekvence začínající zpětným lomítkem a písmenem (např. „\n“). V apostrofech je zvláštním znakem pouze apostrof a odzvláštnění není možné. Konec řádky může být obsažen v obou druzích literálů bez odzvláštnění.
33 Můžete sice použít i „\0“, ale ne, pokud by za ním měla následovat číslice. „\01“ totiž vygeneruje bajt s hodnotou 1, ne nulový bajt a číslici 1.
34 Pozor, výchozí oddělovač je mezera. Chcete-li interpolovat prvky pole bez oddělení, musíte do proměnné $LIST_SEPARATOR nastavit prázdný řetězec.
35 Nebyl-li podřetězec nalezen, funkce vrací -1. Limit u funkce „rindex()“ znamená, že budou ignorovány výskyty podřetězce, které začínají na vyšším indexu, než je uvedený limit.
36 Pokud další shoda nebyla nalezena, funkce vrací undef, resp. next_match() vrací (undef, undef).
37 Nebyla-li další shoda nalezena, vráceno bude prázdné pole. V ostatních případech je záchytem [0] shoda jako celek a počínaje indexem [1] jednotlivé záchyty ze závorek. Všechny záchyty se vracejí ve formě ukazatele na dvouprvkové pole (index začátku, délka záchytu).
38 Shody se vracejí ve formě ukazatele na dvouprvkové pole (index začátku, délka shody).
39 Poznámka: tuto funkci obvykle nepotřebujete, protože do regulárního výrazu můžete interpolovat řetězec bez interpretace pomocí dvojice „\Q“ a „\E“.
40 Podrobnější informace o syntaxi najdete v sekci „Regulární výraz a řetězec náhrady“.
41 Pro nahrazení jen prvního výskytu vypusťte „g“ na konci druhého řádku zaklínadla.
42 Poznámka: výsledek překladu přepíše původní proměnnou, ale není návratovou hodnotou výrazu!
43 Prvky seznamu mohou být skaláry (každý utvoří jeden prvek seznamu) nebo pole a vnořené seznamy (každé pole a vnořený seznam se za běhu rozloží na všechny svoje prvky v náležitém pořadí). Tip: skalárem v seznamu může být i nehodnota undef.
44 Slovo je v tomto případě každá neprázdná posloupnost nebílých znaků oddělená od ostatních slov alespoň jedním bílým znakem. Uvnitř operátoru qw není možné odzvláštnění a zvláštní význam má pouze odpovídající uzavírací závorka a bílé znaky. Forma se složenými závorkami je vhodnější při víceřádkovém použití.
45 Pokud přistupujete k prvku pole vráceného z volání funkce, musíte celé volání obalit ještě do další úrovně kulatých závorek, např. „(f(1, 2))[5]“. U „f(1, 2)[5]“ Perl ohlásí syntaktickou chybu.
46 Přebytečné prvky pole se zahazují. Přebytečné proměnné se vyplní nehodnotou undef.
47 Funkce typy() s více parametry vrací řetězec, který je konkatenací návratových hodnot pro jednotlivé prvky. Význam jednotlivých částí řetězce je popsán v poznámce pod čarou k příkazu pro zjištění typu skaláru.
48 Funkce shift() a pop() vracejí vyjmutý prvek.
49 Poznámka: vkládání na určitý index může být pomalé.
50 Výsledkem je seznam prvků, pro které se poslední příkaz v bloku vyhodnotí jako logická pravda.
51 Pokud je seznam kratší než N prvků, funkce ho vrátí nezměněný.
52 Operátor „map“ funguje přesně jako cyklus „foreach (@pole)“ (tzn. v uvedeném bloku je $ARG odkaz na právě zpracovávaný prvek pole), až na to, že jeho návratovou hodnotou je seznam hodnot posledního provedeného příkazu bloku v každém cyklu. Protože je $ARG odkaz, můžete ho využít k modifikaci prvků původního pole.
53 Tip: místo uložení do pole můžete získanou N-tici rovnou rozložit do proměnných, nebo můžete místo funkce splice() použít opakované volání funkce shift(). Poslední N-tice může být neúplná. Pokud chcete přebytečné prvky zahodit, nahraďte podmínku „!= 0“ za „>= N“.
54 Má-li vstup lichý počet prvků, funkce vypíše varování a k utvoření poslední dvojice doplní „undef“.
55 Poznámka: většina lokalizací nerozlišuje velikost písmen a toto rozlišování u nich nelze zapnout; v češtině např. neexistují pravidla pro odlišné řazení „ch“, „CH“, „cH“ a „Ch“.
56 Pokud si nejste stoprocentně jistý/á, že všechny prvky seznamu (resp. pole) jsou čísla (nebo řetězce vypadající přesně jako čísla), uvažte možnost předběžného přefiltrování seznamu funkcí „grep“ nebo konverzi na čísla funkcí „map“. Porovnávací operátor <=> se může chovat podivně, když se setká s ne-číslem; může vypsat chybové hlášení nebo prvek poslat na konec pole; pravděpodobně však nezpůsobí pád programu.
57 Řadicí blok dostane odkazy na porovnávané skaláry ve speciálních proměnných $a a $b a musí vrátit číslo větší než 0, pokud $a > $b; číslo menší než 0, pokud $a < $b a nulu jinak.
58 Úroveň řazení 2 nerozlišuje velikost písmen; úroveň řazení 3 rozlišuje velikost písmen, ale ne znaky se stejnou řadicí váhou; úroveň řazení 4 rozliší i znaky se stejnou řadicí váhou. Tip 1: pro řazení sestupně prohoďte parametry $a a $b. Tip 2: pro proměnnou $porovnávač můžete zvolit jiný identifikátor.
59 Podmínka je jeden nebo více příkazů, kde výsledek posledního příkazu je otestován na logickou hodnotu. Testovaný prvek (resp. index) se předává pomocí speciální proměnné $ARG. Pokud prvek nebude nalezen, funkce vrátí undef.
60 Podle dokumentace je pořadí prvků v polích vrácených těmito funkcemi stejné, dokud se dané asociativní pole nezmění. Naopak každá jako změna pravděpodobně změní pořadí prvků vracené oběma funkcemi.
61 Pokud prvek neexistuje, čtení vrací undef a přiřazení prvek vytvoří.
62 Pokus o smazání neexistujícího prvku je tiše ignorován.
63 Pro interpretaci návratové hodnoty funkce typy() vyhledejte poznámku pod čarou k zaklínadlu „zjistit typ skaláru“ v této kapitole. Pro interpretaci návratové hodnoty funkce ref() hledejte v dokumentaci Perlu.
64 Analogicky můžete ukazatel na anonymní funkci předat jako parametr jiné funkci. Poznámka: raději se nesnažte získávat ukazatele na vestavěné funkce Perlu; pravděpodobně to nebude fungovat.
65 Poznámka: klíče v asociativním poli jsou nepřiřaditelné, proto ukazatel na ně nelze získat.
66 Uvnitř složených závorek zde nemusí být jen proměnná, ale může to být jakýkoliv výraz, který vrátí příslušný ukazatel (např. volání funkce).
67 Režim je jeden z: „<“: otevřít existující soubor pro čtení; „>“: vytvořit nový/přepsat existující soubor a otevřít pro zápis; „>>“: otevřít pro zápis na konec souboru.
68 Režim je jeden z: „<“: otevřít existující soubor pro čtení; „+<“: otevřít existující soubor pro čtení i zápis; „>“: vytvořit nový/přepsat existující soubor a otevřít jen pro zápis; „+>“: totéž, ale pro zápis i čtení; „>>“: otevřít soubor pro zápis na konec.
69 Deskriptory jsou číslované proudy, které typicky otevírá bash před spuštěním každého procesu. Deskriptory číslo 0, 1 a 2 se nazývají „standardní vstup“, „standardní výstup“ a „standardní chybový výstup. Režim je v tomto případě buď „<“ pro čtení z deskriptoru, nebo „>“ pro zápis do deskriptoru.“
70 Tento příkaz nesmí být použit poté, co už bylo s proudem od otevření manipulováno (např. čtením, zápisem, přesouváním apod.) Proto ho doporučuji používat jen okamžitě po otevření proudu.
71 Perl doplní chybové hlášení o označení zdrojového kódu a číslo řádku.
72 Při čtení za koncem souboru se do proměnné $cíl uloží nehodnota undef.
73 Podle manuálu tyto funkce nejsou příliš efektivní; je vhodnější raději načítat po řádcích s ukončovačem a každou řádku rozdělit po znacích. Při čtení za koncem souboru funkce vracejí undef.
74 Pozor! Mód je zde interpretován v oktalové soustavě, proto ho tak zpravidla musíte zadat. Pokud ho zadáte v desítkové soustavě (např. „777“), nebude fungovat.
75 Pozor, získané pole bude obsahovat i zvláštní položky „.“ a „..“ a všechny skryté soubory a adresáře. Možná budete vrácené pole chtít přefiltrovat funkcí grep() a seřadit.
76 Typ je: 1 pro pojmenovanou rouru; 2 pro znakové zařízení; 4 pro adresář; 6 pro blokové zařízení; 8 pro soubor; 10 pro symbolický odkaz (jen u funkce „lstat“!) a 12 pro soket.
77 Čas se vrací jako celočíselná časová známka Unixu.
78 Mód se vrací jako číslo. Pravděpodobně ho budete chtít vypsat v čitelné podobě funkcí „printf()“ s formátem "%04o".
Líbí se vám tento projekt a chcete, aby byl ještě lepší? Můžete mi s tím pomoci. Zmiňte se o něm technicky zdatným přátelům, opravte překlepy a nahlašte nefunkční zaklínadla, aby mohla být opravena; poskytněte mi zpětnou vazbu nebo se zapojte do vývoje nových kapitol. Další informace na GitHubu v dokumentu Jak se zapojit.
[BY-SA]

Veškerý obsah této stránky (text, obrázky, zdrojový kód) je možno upravovat a šířit pod podmínkami licence Creative Commons Attribution-ShareAlike 4.0 International. Upozorňuji, že uvedená licence vyžaduje uvedení seznamu autorů, licence a zdroje a poskytnutí stejné či kompatibilní licence k provedeným změnám, jsou-li nějaké. Příslušné údaje jsou dostupné na stránce „Přehled autorů“. Šíření obsahu bez těchto údajů nebo šíření upravené verze bez poskytnutí adekvátní licence k provedeným úpravám je pravděpodobně porušení licenčních podmínek a může být postihováno. Poskytování zdrojového kódu při šíření není touto licencí vyžadováno.

Pro nové verze, další informace, aktuální zdrojový kód a možnost se zapojit do projektu „Linux: Kniha kouzel“ navštivte jeho repozitář na GitHubu.