Při psaní skriptů v Bash se s prací s řetězci potýkají nejen zkušení programátoři, ale i nováčci v shellu Bash. To je nejčastěji potřeba při čtení příkazů, které uživatel zadává jako argumenty do spustitelného skriptu, a při zpracování textových souborů. A jedním z nezbytných triků je v tomto případě srovnání strun.

Tento článek se podívá na porovnávání Bashových řetězců a také na některé nuance používání porovnávacích operací a řešení běžných chyb.

Tyto operace umožňují určit, zda jsou porovnávané řetězce stejné:

  • = - rovný, například if [ "$x" = "$y" ]
  • == - synonymum pro operátor "=", například if [ "$x" == "$y" ]
  • != - například ne totéž if [ "$x" != "$y" ]

#!/bin/bash
testuser=anton
if [ $USER = $testuser ]
pak
echo "Vítejte $testuser"
fi

Výsledek skriptu:

Při kontrole rovnosti s příkazem test(synonymní s hranatými závorkami ) jsou brány v úvahu všechny rozdíly v interpunkci a malých a velkých písmenech v porovnávaných řetězcích.

Některé funkce porovnávání řetězců se vzory:

# vrátí hodnotu true, pokud řetězec obsažený v $x začíná "y"
[[ $x == y* ]]
# vrátí hodnotu true, pokud řetězec $x obsahuje přesně dva znaky "y*"
[[ $x == "y*" ]]
# vrátí hodnotu true, pokud $x obsahuje název souboru obsaženého v aktuálním adresáři, který začíná "y"
[ $x == y* ]
# vrátí hodnotu true, pokud se řetězec $x rovná dvěma znakům "y*"
[ "$x" == "y*" ]

Například kontrola bash řetězce, zda začíná na y:

#!/bin/bash
x=yandex
[[ $x == y* ]]
echo $?

Výsledek spuštění kódu:

Skript vypíše 0 (nulu), protože jsme požádali o kód chyby poslední provedené instrukce. Kód 0 znamená, že skript běžel bez chyb. Opravdu, proměnná x $ obsahuje řetězec yandex, který začíná znakem "y". Jinak může být zapsáno "1". Toto je docela šikovný způsob ladění skriptů.

Porovnání řetězců podle abecedy v Bash

Úloha se komplikuje, když se pokoušíte určit, zda je řetězec předchůdcem jiného řetězce ve vzestupném pořadí řazení. Lidé, kteří píší skripty v bash shellu, často narážejí na dva problémy týkající se operací většího a menšího než s porovnáváním řetězců v Linuxu, které mají poměrně jednoduchá řešení:

Za prvé, znaky "větší než" a "menší než" musí být escapovány přidáním zpětného lomítka (\), protože jinak je bude shell považovat za znaky pro přesměrování a řetězce za názvy souborů. Toto je jeden z těch případů, kdy je vystopování chyby poměrně obtížné.

#!/bin/bash
# nesprávné použití operátorů porovnání řetězců
val1=baseball
val2=hokej
if [ $val1 > $val2 ]
pak

jiný

fi

Co se stane, když porovnáte bash řetězce:

Jak můžete vidět, samotný symbol "větší než" ve své přímé podobě vedl k nesprávným výsledkům, ačkoli nebyly generovány žádné chyby. V tomto případě tento znak způsobil přesměrování výstupního proudu, takže nebyly nalezeny žádné syntaktické chyby a v důsledku toho byl soubor s názvem hokej:

Chcete-li tuto chybu opravit, musíte ukončit znak ">", aby podmínka vypadala takto:

...
if [ $val1 \> $val2 ]
...

Pak bude výsledek programu správný:

Za druhé, řetězce uspořádané pomocí operátorů „větší než“ a „méně než“ jsou uspořádány jinak, než tomu je u příkazu seřadit. Zde jsou problémy hůře rozpoznatelné a nemusí se s nimi vůbec setkat, pokud se při porovnání nerozlišují malá a velká písmena. V týmu seřadit a test Srovnání je jiné:

#!/bin/bash
val1=Testování
val2=testování
if [ $val1 \> $val2 ]
pak
echo "$val1 je větší než $val2"
jiný
echo "$val1 je menší než $val2"
fi

Výsledek kódu:

V týmu testřetězce s velkými písmeny budou nejprve před řetězcem s malými písmeny. Ale pokud jsou stejná data zapsána do souboru, na který se pak použije příkaz seřadit, pak budou na prvním místě řetězce s malými písmeny:

Rozdíl mezi jejich prací je v tom test pro určení pořadí řazení se za základ bere uspořádání znaků podle ASCII tabulky. V seřadit používá také pořadí řazení určené pro jazyková nastavení místního nastavení.

Kontrola řetězce na prázdnou hodnotu

Porovnání pomocí operátorů -z a -n používá se k určení, zda proměnná obsahuje obsah. Tímto způsobem můžete najít prázdné řádky v bash. Příklad:

#!/bin/bash
val1=testování
val2=""
# zkontroluje, zda je řetězec prázdný
pokud [ -n $val1 ]
pak
echo "Řetězec "$val1" není prázdný"
jiný
echo "Řetězec "$val1" je prázdný"
fi
# zkontroluje, zda je řetězec prázdný
if [ -z $val2 ]
pak
echo "Řetězec "$val2" je prázdný"
jiný
echo "Řetězec "$val2" není prázdný"
fi
if [ -z $val3 ]
pak
echo "Řetězec "$val3" je prázdný"
jiný
echo "Řetězec "$val3" není prázdný"
fi

Výsledek kódu:

Tento příklad vytvoří dvě řetězcové proměnné - val1 a val2. Úkon -n určuje, zda má proměnná val1 nenulová délka a -z kontroly val2 a val3 na nulu. Je pozoruhodné, že posledně jmenovaný nebyl definován až do okamžiku srovnání, ale interpret se domnívá, že jeho délka je stále rovna nule. Tato nuance by měla být zohledněna při různých kontrolách scénářů. A pokud si nejste jisti, jaká hodnota je obsažena v proměnné a zda je vůbec nastavena, měli byste ji zkontrolovat pomocí operátoru -n nebo -z a teprve poté jej používat k určenému účelu.

Stojí za to věnovat pozornost funkci -n. Pokud je k testování předána nedeklarovaná nebo prázdná proměnná, vrátí hodnotu true, nikoli false. V takových případech byste měli kontrolovaný řetězec (proměnnou) uzavřít do dvojitých uvozovek, aby vypadal takto:

...
if [ -n "$val1" ]
...

závěry

Prezentované operace porovnání řetězců Bash mají určité nuance, které stojí za to pochopit, aby se zabránilo chybám ve skriptování. Ale takových situací je v praxi mnoho, takže pamatovat si vše (a ještě více popisovat) nebude fungovat.

if-else podmínka použitá ve skriptech BASHČasto. Samotná podmínka má poněkud zvláštní tvar [[ podmínka ]]. Dávejte pozor na odsazení. Bez nich podmínka nebude fungovat. Dávám seznam logických operátorů pro podmínku [[ ? ]]:

Seznam logických operátorů, které
používá se pro konstrukci if-then-else-fi

#!/bin/bash if [[ $1 > 2 ]] pak # if [[ ? ]] echo $1" větší než 2" jinak # pokud to není pravda echo $1" menší než 2 nebo 2" fi

Některým z vás bude operátor rovnosti -eq připadat zvláštní. Zkuste použít známé operátory >

Řekněme, že máte skript a je vyžadováno ověření uživatele. Pokud uživatel není root, skript se zastaví.

#!/bin/bash if [ "$(whoami)" != "root" ]; pak echo "Nemáte oprávnění ke spuštění $0." exit1; fi

Často je potřeba zkontrolovat hodnotu proměnné. Pokud v proměnné nic není, můžete skript zastavit.

#!/bin/bash if [ -n "$num" ]; pak "proměnná má něco a můžete spustit další proces" jinak echo "prázdná proměnná, zastavte skript" exit 0; fi

Pokud je proměnná prázdná, lze ji vyplnit.

#!/bin/bash if [ -z "$num" ]; potom echo "proměnná je prázdná" num=1 else echo "num="$num fi

Prázdné proměnné lze přiřadit výchozí hodnotu. Tento záznam je kratší než v předchozím příkladu.

#!/bin/bash # Zapište DEFAULT, pokud nejsou žádné argumenty příkazového řádku [ -z "$arg1" ] && arg1=DEFAULT echo $arg1

Ve skriptech shellu Bash můžeme provádět porovnávání čísel. Chcete-li provést operaci porovnání čísel v Bash, musíte použít stav "test" v rámci if nebo smyčky. V tomto příspěvku vám řekneme, jak porovnávat čísla v bash.

Operátory pro porovnání bash čísel

operátorco dělápříklad
-ekvporovnat číslice v bash pro rovnost, vrátí 0, pokud se rovnáif [ $a -eq $b ] pak
-geporovnávání čísel v bash, pokud jsou větší nebo rovno. Výsledek vrátí 0, pokud je větší nebo rovenif [ $a -ge $b ] then
-gtporovnává čísla v bash, pokud jsou větší než.if [ $a -gt $b ] pak
-leporovnává čísla v bash, pokud jsou menší nebo rovna.if [ $a -le $b ] then
-ltporovnává čísla v bash, pokud jsou menší.if [ $a -lt $b ] then
-neporovnává čísla v bash, pokud nejsou stejná nebo ne.if [ $a -ne $b ] then

Podrobné příklady operátorů porovnání čísel v Bash:

1. operátor-ekv

Tento operátor porovnává čísla, zkontroluje, zda je hodnota rovna nebo ne. Pokud se rovná, vrátí se 0.

# cat test.sh #!/bin/bash echo "zadat hodnotu proměnné" přečíst echo "zadat hodnotu proměnné" přečíst b if [ $a -eq $b ] potom echo "Vrátit hodnotu:: $?" echo "a a b jsou stejné" jinak echo "Vrácená hodnota::$?" echo "a a b nejsou stejné" fi #

Provedení:

# sh test.sh zadejte hodnotu proměnné 2 zadejte hodnotu proměnné 3 Návratová hodnota:: 1 aab se nerovnají # sh test.sh zadejte hodnotu proměnné 2 zadejte hodnotu proměnné 2 Návratová hodnota:: 0 aab se rovnají #

Ve výše uvedeném příkladu jsme poprvé vzali čísla 2 a 3 a systém vrátil hodnotu 1, ale když jsme vzali stejné hodnoty pro a a b, proměnná vrátí nulu.

2. operátor-ge

Tento operátor porovnává čísla a kontroluje hodnoty větší nebo rovné. Pokud je hodnota větší nebo rovna, pak je její návratová hodnota 0.

# cat test1.sh #!/bin/bash #diff program pro -ge echo "zadejte hodnotu pro proměnnou" přečtěte si echo "zadejte hodnotu pro proměnnou b" přečtěte si b if [ $a -ge $b ] potom echo "vraťte hodnotu : :$?" echo "a je větší nebo rovno b" jinak echo "návratová hodnota::$?" echo "a není větší nebo rovno b" fi #

3. operátor -gt

Tento operátor porovnání čísel otestuje, zda je číslo větší. Pokud je hodnota větší, vrátí 0.

# test kočky2.sh #!/bin/bash #differ for -gt b=100 echo "Zadejte hodnotu větší než 100" čtěte a if [ $a -gt $b ] pak echo "Velmi dobře" jinak echo "Nepříliš dobrý "fi

4. operátor-le

Tento operátor porovnávání čísel otestuje hodnoty menší nebo rovné. Pokud je menší nebo rovna, návratová hodnota je 0.

#diff program pro -le b=5 echo "zadejte hodnotu menší nebo rovnou 5" přečti a if [ $a -le $b ] potom echo "správně" jinak echo "nepravda" fi #

5. operátor-lt

Tento operátor porovnání čísel bude testovat hodnoty za méně peněz. Pokud je číslo menší, návratová hodnota je 0.

Porovnávání řetězců v Bash nezpůsobuje žádné problémy, dokud nevznikne úkol porovnat dva řetězce bez ohledu na velikost písmen. Uvedu několik možností řešení problému, který sám používám. Charakteristickým rysem těchto řešení je použití pouze vestavěných funkcí prostředí Bash.

Nejprve vytvořím dvě proměnné str1 a str2 obsahující řetězce, které se mají porovnávat. Budou použity v následujících příkladech kódu.

#!/bin/bash str1 = "Řetězec k porovnání" str2 = "řetězec k porovnání"

První verze porovnání řetězců bez ohledu na velikost písmen, kterou chci navrhnout, používá ovládání možností shellu pomocí vestavěného příkazu shopt.

shopt -s nocasematch [[ $str1 == $str2 ]] && echo "match" || echo "nesouhlasí" shopt -u nocasematch

Další verze porovnávání řetězců bez ohledu na velikost písmen je založena na principu samopřehazování řetězců do společného pouzdra. Tato varianta kódu funguje na Bash verze 4 a novější. Použití na dřívější verzi Bash bude mít za následek chybu.

Chcete-li tedy porovnat řetězce přetypované na malá písmena, můžete použít následující kód.

[[ " $( str1, ) " == " $( str2, ) " ]] && echo "shoda" || echo "nesouhlasí"

Pokud chcete převést porovnávané řetězce na velká písmena, můžete použít následující kód.

[[ " $( str1 ^^ ) " == " $( str2 ^^ ) " ]] && echo "match" || echo "nesouhlasí"

Alternativně mohou být řetězce vynuceny v době deklarace proměnné. To se provádí pomocí vestavěného příkazu deklarovat shell.

Chcete-li deklarovat proměnnou obsahující text malými písmeny, použijte následující kód.

#!/bin/bash deklarovat -l str = "Řetězec případu velblouda"

V důsledku provedení tohoto kódu bude proměnná str obsahovat řetězec s malými písmeny, a to navzdory skutečnosti, že přiřazovaný řetězec byl zapsán s velkými písmeny. Velikost písmen řetězce již nastaveného v proměnné můžete změnit následovně.

#!/bin/bash str = "Řetězec případu velblouda" deklarovat -l str str = $str echo $str

Chcete-li převést řetězec na velká písmena, ve výše uvedeném příkladu kódu byste měli změnit volání příkazu deklarovat pomocí přepínače -u namísto přepínače -l.

Nyní lze porovnání řetězců bez ohledu na velikost písmen pomocí příkazu deklarovat následovně.

deklarovat -l str1_l = $str1 deklarovat -l str2_l = $str2 [[ $str1_l == $str2_l ]] && echo "match" || echo "nesouhlasí"

Kterékoli z těchto porovnání řetězců bez ohledu na velikost písmen lze použít ve skriptování Bash. Pokud tedy používáte Bash verze 4 a vyšší, můžete si vybrat tu, která se vám nejvíce líbí. Pokud je verze Bash menší než 4, pak by se měla použít první možnost s uvedením možnosti nocasematch pomocí zabudovaného shellu shopt.

Toto téma je čtvrtým tématem v jazykové sérii bash shell. Bude mluvit o takových kontrolních strukturách jazyka, jako jsou podmíněné příkazy. Než však přistoupíme k jejich popisu, je nutné se pozastavit nad některými nuancemi, díky nimž bude zvážení níže uvedeného materiálu srozumitelnější.
Nejprve se podívejme, co je seznam příkazů. Seznam příkazů je jeden příkaz, kanál nebo sekvence příkazů/řádků oddělených jedním z následujících operátorů: ";", "&&", "||", ukončený středníkem.
; - operátor sekvenčního provádění několika příkazů. Každý následující příkaz se začne provádět až po dokončení předchozího (ať už úspěšného nebo ne);
&& - operátor provedení příkazu až po úspěšném provedení předchozího;
|| - příkaz pro provedení příkazu až po chybném provedení předchozího.
Kód úspěchu je 0 a kód chyby není nula (v závislosti na typu chyby). Nezaměňujte s běžnými programovacími jazyky, když 1 je pravda a 0 je nepravda.
Nyní můžeme přistoupit k přímému zvažování podmíněných příkazů.

operátor varianty případu

Obecná syntaxe příkazu case je:

case value in
šablona1) seznam1;;
vzor2 | šablona3) seznam2;;
esac

Logická posloupnost provedení příkazu case:
a) vyhledá se první vzor odpovídající hodnotě;
b) je-li nalezen, provede se seznam jemu odpovídajících příkazů ukončený ";;";
c) kontrola je přenesena na operátory po konstrukci případu.
Vzor a seznam jsou odděleny znakem ")". Jednomu seznamu příkazů může odpovídat několik podmínek, v takovém případě musí být odděleny symbolem "|".
V šablonách můžete použít znaky "*", "?", "", které byly popsány v druhém tématu cyklu. S jejich pomocí můžete implementovat instrukci, která funguje jako výchozí v příkazu switch takových jazyků jako C, PHP.
Uvedu příklad použití case:
echo -n "[Universal Viewer] Určete název souboru: "; read case "$File" in *.jpg|*.gif|*.png) eog $File ;; *.pdf) evince $Soubor ;; *.txt) méně $Soubor ;; *.html) firefox $Soubor ;; /dev/*) echo "No, to jsou děsivé soubory." ;; *) echo "Dobře, dobře - ne tak univerzální." echo "Neznám tento typ souboru. Nevím, jak ho zobrazit." ;; esac
Další příklad použití konstrukce případu:
echo "Chyba. Komu mám poslat zprávu?" echo "Šéfovi: b" echo "Kolegům: c" echo "Nikomu: žádný klíč" číst případ odpovědi $odpověď v b|B) mail –s "protokol chyb" šéf< error.log;; c|C) mail –s "Help! error log" –c denis nick < error.log;; *) echo "error"; exit;; esac

Podmíněný příkaz if

Obecná syntaxe příkazu if je:

pokud seznam1 pak
seznam2

fi

Hranaté závorky zde označují volitelné konstrukce. Logická posloupnost provedení příkazu case:
a) provede se seznam1;
b) pokud je proveden bez chyb, provede se list2. Jinak se provede list3, a pokud se dokončí bez chyby, list4. Pokud list3 také vrátí kód chyby, provede se list5;
c) řízení je přeneseno na operátory po konstrukci if.
Uvedu příklad použití, pokud:
if grep -q Bash soubor pak echo "Soubor obsahuje alespoň jedno Bash slovo." fi
Když jsou if a then na stejném řádku, pak konstrukce if a then musí končit středníkem. Například:
$if[$? –ne0]; pak echo "Chyba"; fi
Nyní, s vědomím, že je možné umístit if a then na stejný řádek, přepišme výše uvedený příklad:
if grep -q Bash soubor; pak echo "Soubor obsahuje slovo Bash." fi

testovací příkaz a podmíněné výrazy

Ve výše uvedeném příkladu se místo analýzy výstupního kódu použije kontrola stavu. Dvě formy takového testu jsou ekvivalentní: vestavěný příkaz testu a [podmínka]. Chcete-li například zkontrolovat, zda soubor existuje, napište:
test -e<файл>
nebo
[-E<файл> ]
Pokud jsou použity hranaté závorky, musí být od sebe odděleny mezerou, protože "[" je název příkazu a "]" je požadovaný poslední argument pro jeho ukončení.
Pokud je podmínka úspěšně zkontrolována, je vrácena 0, a pokud je nepravda, kód chyby je 1.
Příkaz test může zkontrolovat, zda je řetězec prázdný. Neprázdný řetězec má za následek návratový kód 0. Prázdný, respektive - 1. Například:
$ test $USER; echo $? 0
Konstrukce "" je všestrannější než "". Tato rozšířená verze testovacího příkazu. Uvnitř této konstrukce se neprovádí žádná další interpretace názvů souborů a neprovádí se žádné rozdělování argumentů na samostatná slova, ale je povoleno nahrazování parametrů a příkazů. Například:
file=/etc/passwd if [[ -e $file ]] potom echo „Nalezen soubor s heslem“. fi
Konstrukce "" je vhodnější než "", protože pomůže vyhnout se některým logickým chybám. Například operátory "&&", "||", "<" и ">" uvnitř "" jsou dokonale platné, zatímco uvnitř "" generují chybové zprávy.
Konstrukce "(())" umožňuje výpočet aritmetických výrazů uvnitř. Pokud je výsledek výpočtu nula, vrátí se chybový kód. Nenulový výsledek výpočtu dává návratový kód 0. To je přesný opak testu a instrukcí "" diskutovaných výše.
Příkaz if umožňuje vnořené kontroly:
if echo "Další *if* je uvnitř prvního *if*." if [[ $comparison = "integer" ]] pak ((a< b)) else [[ $a < $b ]] fi then echo "$a меньше $b" fi

Podmíněné výrazy lze kombinovat pomocí obvyklých logických operací:
! <выражение>- popření;
<выражение1>-A<выражение2>- logické AND;
<выражение1>-Ó<выражение2>- logické NEBO.

Elementární podmíněné výrazy pro soubory:
-e - soubor existuje;
-f - běžný soubor (nikoli adresář nebo soubor zařízení);
-s - nenulová velikost souboru;
-d - soubor je adresář;
-b - soubor je blokové zařízení (disketa, cdrom atd.);
-c - soubor je znakové zařízení (klávesnice, modem, zvuková karta atd.);
-p - soubor je roura;
-h - soubor je symbolický odkaz;
-L - soubor je symbolický odkaz;
-S - soubor je soket;
-t - soubor je spojen s koncovým zařízením;
-r - soubor je čitelný (pro uživatele, který spustil skript);
-w - do souboru lze zapisovat (uživateli, který skript spustil);
-x - soubor je dostupný ke spuštění (uživateli, který skript spustil);
-g - je nastaven příznak (sgid) pro soubor nebo adresář;
-u - (suid) příznak pro soubor je nastaven;
-k - je nastaven příznak sticky bit;
-O - ​​jste vlastníkem souboru;
-G - patříte do stejné skupiny jako soubor;
-N - soubor byl změněn od posledního čtení;
soubor1 -nt soubor2 – soubor1 je novější než soubor2;
soubor1 -ot soubor2 – soubor1 je starší než soubor2;
soubor1 -ef soubor2 - soubor1 a soubor2 jsou pevné odkazy na stejný soubor.

Elementární podmíněné výrazy pro porovnávání řetězců:
-z řetězec – délka řetězce je 0;
-n řetězec – délka řetězce není rovna 0;
řetězec1 == řetězec2 – řetězce se shodují (podobně jako „=“);
řádek1 !== řádek2 – řádky se neshodují (podobně jako „!=“);
řádek1< строка2 – строка1 предшествует строке2 в лексикографическом порядке;
řádek1 > řádek2 - řádek1 následuje po řádku2 v lexikografickém pořadí.
Aritmetický podmíněný výraz má formát:
argument1 operace argument2 kde argumenty jsou celá čísla a jsou povoleny následující operace:
-eq - rovný;
-ne - nerovná se;
-lt - méně;
-le - menší nebo rovno;
-gt - více;
-ge - větší nebo rovno;
< - меньше (внутри двойных круглых скобок);
<= - меньше или равно (внутри двойных круглых скобок);
> - větší než (uvnitř dvojitých závorek);
>= - větší nebo rovno (uvnitř dvojitých závorek).

Přepišme předchozí příklad pomocí příkazu if:
echo "Chyba. Komu mám poslat zprávu?" echo "Šéfovi: b" echo "Kolegům: c" echo "Nikomu: jakýkoli klíč" read answer if [ "$answer" == "b" –o "$answer" == "B" ]; pak mail –s "protokol chyb" šéf< error.log; elif [ "$answer" == "c" –o "$answer" == "C" ]; then mail –s "Help! error log" –c denis nick < error.log; else echo "error"; exit; fi

V příštím tématu se budu nadále zabývat řídicími strukturami bash shellu. Konkrétně budou uvažovány operátory smyčky. A teď čekám na komentáře a kritiku :).

UPD: Díky uživateli