[[ " stop start status " =~ " $2 " && (($#<3)) ]] || { echo "Usage $0 file_name command"; exit 1;}Con frecuencia uso la solución anterior para verificar el rango de entrada de mi script Bash.
Ahora me doy cuenta de que la expresión aritmética extendida (()) parece estar suprimida dentro del corchete doble [[]] .
Para ilustrar el problema:
a=start; n=1; [[ " stop start status " =~ " $a " && (($n<3)) ]] && echo ok || echo bad ok a=start; n=5; [[ " stop start status " =~ " $a " && (($n<3)) ]] && echo ok || echo bad bad # But: a=start; n=100; [[ " stop start status " =~ " $a " && (($n<3)) ]] && echo ok || echo bad okEl resultado anterior es falso porque n no es menor que 3 si se tratan como números. Esta es la solución correcta:
a=start; n=100; [[ " stop start status " =~ " $a " ]] && (($n<3)) && echo ok || echo bad bad a=start; n=1; [[ " stop start status " =~ " $a " ]] && (($n<3)) && echo ok || echo bad okLa página de manual de GNU bash para [[..]] explica que el operador ejecuta una expresión condicional y
Devuelve un estado de
0o1dependiendo de la evaluación de la expresión condicionalexpression. Las expresiones se componen de los primarios que se describen a continuación en Expresiones condicionales de Bash .
Pero el operador aritmético no es parte de las expresiones condicionales compatibles ( primarias ) 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 un contexto aritmético sino en una comparación lexicográfica (cadena) tan simple como
[[ 100 < 3 ]] que siempre resultará verdadero, porque los valores ASCII para 1 , 0 , 0 aparecen antes que 3
Pero dentro de [[..]] las operaciones aritméticas son compatibles si usa -lt , -gt
arg1 OP arg2OP es uno de
-eq,-ne,-lt,-le,-gto-ge. Estos operadores binarios aritméticos devuelven verdadero siarg1es igual a, no igual a, menor que, menor que o igual a, mayor que, o mayor que o igual aarg2, respectivamente.
Entonces, ¿habías escrito tu expresión como
a=start; n=100; [[ " stop start status " =~ " $a " && $n -lt 3 ]] && echo ok || echo bad badhabría funcionado como se esperaba.
O incluso si hubiera forzado el uso de la expresión aritmética con el prefijo $ antes de ((..)) y lo hubiera escrito 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 de que se evalúe [[..]] y la salida resultante se evalúe 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 cadena unaria, no una expresión de comparación vacía como
$(( 5 < 3 )) 0 [[ -n 0 ]] El operador de prueba toma el resultado de la evaluación aritmética 0 (falso) como una entidad distinta de cero y afirma que es verdadero en el lado derecho de && . Lo mismo se aplicaría para el otro caso también, por ejemplo, digamos 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 la declaración aritmética. Sin embargo, dentro de [[ , no puede usar otras declaraciones. Sin embargo, puede usar paréntesis para agrupar expresiones, así que eso es (( ... )) : una "doble grupo". 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 necesita ajustar 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. Prefiere una declaración if en su lugar.
if [[ " stop start status " =~ " $2 " ]] && (($#<3)); then echo "Usage $0 file_name command" exit 1 fi