La página man de GNU bash para [[..]]
explica que el operador ejecuta una expresión condicional y
Devuelve un estado de 0
o 1
dependiendo de la evaluación de la expresión condicional expression
. Las expresiones se componen de las primarias que se describen a continuación en Expresiones condicionales de Bash.
Pero el operador aritmético es no parte de las expresiones condicionales admitidas (primaries ) dentro de [[..]]
lo que significa que la expresión se ve obligada a ejecutarse como una comparación de cadenas, es decir,
(( $n < 3))
no se ejecuta en contexto aritmético pero tan simple comparación lexicográfica (cadena) como
[[ 100 < 3 ]]
que siempre resultará verdadero, porque los valores ASCII para 1
, 0
, 0
aparecer antes de 3
Pero dentro [[..]]
las operaciones aritméticas son compatibles si usa -lt
, -gt
arg1 OP arg2
OP es uno de -eq
, -ne
, -lt
, -le
, -gt
, o -ge
. Estos operadores binarios aritméticos devuelven verdadero si arg1
es igual a, no igual a, menor que, menor que o igual a, mayor que, o mayor que o igual a arg2
, respectivamente.
Así que habías escrito tu expresión como
a=start; n=100; [[ " stop start status " =~ " $a " && $n -lt 3 ]] && echo ok || echo bad
bad
habría funcionado como se esperaba.
O incluso si hubiera forzado el uso de expresiones aritméticas al anteponer $
antes de ((..))
y lo escribió como se muestra a continuación (tenga en cuenta que bash no tiene un comportamiento documentado para $((..))
dentro de [[..]]
). El comportamiento esperado probable es que la expresión aritmética se expanda antes del [[..]]
se evalúa y la salida resultante se evalúa en un contexto de cadena como [[ 0 ]]
lo que significa una cadena no vacía.
a=start; n=5; [[ " stop start status " =~ " $a " && $(( $n < 3 )) ]] && echo ok || echo bad
El resultado aún se vería mal, porque la expresión aritmética dentro de [[..]]
se descompone en una expresión de comparación de cadena unaria no vacía como
$(( 5 < 3 ))
0
[[ -n 0 ]]
El resultado de la evaluación aritmética 0
(falso) es tomado como una entidad distinta de cero por el operador de prueba y afirma verdadero en el lado derecho de &&
. Lo mismo se aplicaría para el otro caso, p. di n=1
$(( 1 < 3 ))
1
[[ -n 1 ]]
En pocas palabras, use los operandos correctos para la operación aritmética dentro de [[..]]
.
((
es una "palabra clave" que introduce el enunciado aritmético. Dentro de [[
, sin embargo, no puede usar otras declaraciones. Tu puedes Sin embargo, use paréntesis para agrupar expresiones, eso es lo que (( ... ))
es:un "grupo doble" redundante. Los siguientes son todos equivalentes, debido a las precedencias de <
y &&
:
[[ " stop start status " =~ " $2 " && (($#<3)) ]]
[[ " stop start status " =~ " $2 " && ($#<3) ]]
[[ " stop start status " =~ " $2 " && $#<3 ]]
Si desea una comparación de enteros, use -lt
en lugar de <
, pero tampoco es necesario que quepa todo dentro de [[ ... ]]
. Puede usar una declaración condicional y una declaración aritmética juntas en una lista de comandos.
{ [[ " stop start status " =~ " $2 " ]] && (($#<3)) ; } || { echo "Usage $0 file_name command"; exit 1;}
En este caso, ... && ... || ...
funcionará de la manera esperada, aunque en general ese no es el caso. Prefiero un if
declaración en su lugar.
if [[ " stop start status " =~ " $2 " ]] && (($#<3)); then
echo "Usage $0 file_name command"
exit 1
fi