En el script de shell podemos sustituir expr $a*$b
con $(($a+$b))
.
Pero por qué no solo con (($a+$b))
, porque en cualquier recurso está escrito que (())
es para el cálculo de números enteros.
Entonces usamos $(())
cuando hay variables en lugar de valores enteros, ¿verdad? ¿Y qué deberíamos usar en lugar de $(())
cuando las variables pueden recibir valores flotantes?
Comentarios
- Ver también unix.stackexchange.com/questions/149823/…
Respuesta
-
Para aritmética,
expr
es arcaico. No lo use. * -
$((...))
y((...))
son muy similares. Ambos solo hacen cálculos con números enteros. La diferencia es que$((...))
devuelve el resultado del cálculo y((...))
no. Por lo tanto,$((...))
es útil enecho
declaraciones:$ a=2; b=3; echo $((a*b)) 6
((...))
es útil cuando desea asignar una variable o establecer un código de salida:$ a=3; b=3; ((a==b)) && echo yes yes
-
Si desea flotar cálculos de puntos, utilice
bc
oawk
:$ echo "4.7/3.14" | bc -l 1.49681528662420382165 $ awk "BEGIN{print 4.7/3.14}" 1.49682
* Por otro lado, expr
sigue siendo útil para el manejo de cadenas cuando los globs no son lo suficientemente buenos y se necesita un método POSIX para manejar expresiones regulares.
Comentarios
- Si expr es arcaico, ¿qué deberíamos usar en lugar del texto expr? '. * '
- Si
s
es una variable de shell, su longitud es${#s}
- $ {#} significa un número de argumentos y $ (# s} significa un número de caracteres de una variable, ¿verdad?
- Sí. Eso ' es correcto.
- @Stranger Muchos usos de
expr STRING : REGEX
se pueden escribir comocase STRING in PATTERN)
.expr
solo es útil cuando REGEX no puede ' t expresarse con comodines de shell.
Answer
expr es antiguo, pero se me ocurre un uso limitado. Digamos que desea buscar una cadena. Si desea permanecer POSIX con grep, debe usar una tubería:
if echo november | grep nov then : do something fi
expr puede hacer esto sin una tubería:
if expr november : nov then : do something fi
el único problema es que expr funciona con cadenas ancladas, por lo que si desea hacer coincidir después del principio, debe cambiar el REGEXP:
if expr november : ".*ber" then : do something fi
Con respecto a (( ))
, esta construcción no es POSIX , por lo que debe evitarse.
Con respecto a $(( ))
, no es necesario que incluya el signo de dólar:
$ fo=1 $ go=2 $ echo $((fo + go)) 3
Comentarios
- Muchos usos de
expr STRING : REGEX
pueden escribirse comocase STRING in PATTERN)
.expr
solo es útil cuando REGEX no puede ' t expresarse con comodines de shell.
Respuesta
Parece que los siguientes programas hacen más o menos lo mismo y en realidad no difieren. Pero eso no es cierto.
#!/bin/bash s=-1000 for (( i=0; i<1000000; i++ )), do s=$((s+1)) echo $s
Esta es la forma correcta de implementar esto. La expresión s + 1 es evaluada por el shell y puede asignarse a una variable.
#!/bin/bash s=-1000 for (( i=0; i<1000000; i++ )), do s=`expr $s+1` echo $s
Aquí la expresión será calculada por el programa expr, que no es un shell incorporado sino un programa externo de Unix. Entonces, en lugar de simplemente agregar 1 ys, se debe iniciar un programa y su salida debe leerse y escribirse en la variable. Iniciar un programa requiere muchos recursos y mucho tiempo. Y este programa se ejecuta 1000000 veces. Entonces el programa será mucho más lento que el anterior. Sin embargo, el código funciona correctamente.
#!/bin/bash -e s=-1000 for (( i=0; i<1000000; i++ )), do ((s=s+1)) echo $s
Si no se establece la opción -e, el programa también funcionará correctamente. Pero si se establece -e cuando s = -1 y ((s = s + 1)) se calcula. La expresión s = s + 1 se evalúa como 0 y el código de salida de ((0)) es> 0, que es interpretado como un error por el shell y el shell sale del programa.
La razón para establecer el indicador -e es que es la forma más sencilla de procesar errores: deténgase si ocurre un error.