Manuální stránka GNU bash pro [[..]]
vysvětluje, že operátor spustí podmíněný výraz a
Vrátí stav
0
nebo1
v závislosti na vyhodnocení podmíněného výrazuexpression
. Výrazy se skládají z primárních položek popsaných níže v části Bash Conditional Expressions.
Ale aritmetický operátor není část podporovaných podmíněných výrazů (primární ) uvnitř [[..]]
což znamená, že výraz je nucen běžet jako porovnání řetězců, tj.
(( $n < 3))
není spuštěn v aritmetickém kontextu ale stejně prosté lexikografické (řetězcové) srovnání jako
[[ 100 < 3 ]]
což bude vždy mít hodnotu true, protože hodnoty ASCII pro 1
, 0
, 0
objeví se před 3
Ale uvnitř [[..]]
aritmetické operace jsou podporovány, pokud použijete -lt
, -gt
arg1 OP arg2
OP je jeden z
-eq
,-ne
,-lt
,-le
,-gt
nebo-ge
. Tyto aritmetické binární operátory vrátí hodnotu true, pokudarg1
je rovno, ne rovno, menší než, menší nebo rovno, větší než nebo větší nebo rovnoarg2
, respektive.
Napsali byste tedy svůj výraz jako
a=start; n=100; [[ " stop start status " =~ " $a " && $n -lt 3 ]] && echo ok || echo bad
bad
fungovalo by to podle očekávání.
Nebo i když jste vynutili použití aritmetického výrazu předponou $
před ((..))
a zapsal to, jak je uvedeno níže (všimněte si, že bash nemá zdokumentované chování pro $((..))
uvnitř [[..]]
). Pravděpodobně očekávané chování je, že aritmetický výraz je rozšířen před [[..]]
je vyhodnocen a výsledný výstup je vyhodnocen v kontextu řetězce jako [[ 0 ]]
což znamená neprázdný řetězec.
a=start; n=5; [[ " stop start status " =~ " $a " && $(( $n < 3 )) ]] && echo ok || echo bad
Výsledek by stále vypadal špatně, protože aritmetický výraz uvnitř [[..]]
se rozloží na unární řetězec, nikoli prázdný porovnávací výraz jako
$(( 5 < 3 ))
0
[[ -n 0 ]]
Výsledek aritmetického vyhodnocení 0
(false) je operátorem testu brán jako nenulová entita a platí true na pravé straně &&
. Totéž by platilo pro jiný případ také např. řekněte n=1
$(( 1 < 3 ))
1
[[ -n 1 ]]
Stručně řečeno, použijte správné operandy pro aritmetické operace uvnitř [[..]]
.
((
je "klíčové slovo", které zavádí aritmetický příkaz. Uvnitř [[
, ale nemůžete použít jiné příkazy. můžete k seskupování výrazů však použijte závorky, takže to je to, co (( ... ))
je:nadbytečná "dvojitá skupina". Následující jsou všechny ekvivalentní kvůli prioritám <
a &&
:
[[ " stop start status " =~ " $2 " && (($#<3)) ]]
[[ " stop start status " =~ " $2 " && ($#<3) ]]
[[ " stop start status " =~ " $2 " && $#<3 ]]
Pokud chcete srovnání celých čísel, použijte -lt
místo <
, ale také nemusíte všechno vměstnat do [[ ... ]]
. V seznamu příkazů můžete použít podmíněný a aritmetický příkaz společně.
{ [[ " stop start status " =~ " $2 " ]] && (($#<3)) ; } || { echo "Usage $0 file_name command"; exit 1;}
V tomto případě ... && ... || ...
bude fungovat tak, jak očekáváte, i když obecně tomu tak není. Preferujte if
místo toho prohlášení.
if [[ " stop start status " =~ " $2 " ]] && (($#<3)); then
echo "Usage $0 file_name command"
exit 1
fi