bash -e sale cuando let o expr se evalúa a 0

19

Tengo un script bash que establece -e para que el script salga en cualquier estado de salida! = 0.

Estoy tratando de hacer una aritmética de shell básica asignada a las variables y, a veces, la expresión es igual a 0, lo que hace que el estado de salida del comando let o expr sea "1".

Aquí hay un ejemplo:

#!/bin/bash -ex
echo "Test 1"
Z=`expr 1 - 1` || true
echo "Z will print"
let "A=4 - 4"
echo "A WILL NEVER PRINT $A"
Y=`expr 1 - 1`
echo "Y WILL NEVER PRINT $Y"
X=$(expr 2 - 2)
echo "X WILL NEVER PRINT $X"

El resultado es:

$ ./test_error.sh 
+ echo 'Test 1'
Test 1
++ expr 1 - 1
+ Z=0
+ true
+ echo 'Z will print'
Z will print
+ let 'A=4 - 4'

Mi pregunta es cuál es la forma idiomática de secuencias de comandos bash para permitir que la secuencia de comandos falle en errores de salida reales y no en aritmética básica igual a 0. Podría sufijar todas esas expresiones con:

A=`expr $C - $D`    || true

Pero eso parece hacky.

Dougnukem
fuente

Respuestas:

16

No lo use exprpara aritmética. Durante mucho tiempo ha quedado obsoleto: los shells ahora tienen aritmética incorporada, con la $((…))construcción (POSIX), o con la construcción let(ksh / bash / zsh) o la ((…))construcción (ksh / bash / zsh).

lety ((…))devuelve 1 (un código de estado de falla) si la última expresión evaluada es 0. Para evitar que su secuencia de comandos salga por debajo set -e, organice que la última expresión no devuelva 0, por ejemplo:

let "a = 2 - 2" 1
((a = 2 - 2, 1))

Alternativamente, usa el || trueidioma:

((a = 2 - 2)) || true

Alternativamente, haga su aritmética adentro $((…))y sus tareas afuera. Una asignación devuelve el estado de la última sustitución de comando en el valor, o 0 si no hay sustitución de comando, por lo que está a salvo. Esto tiene el beneficio adicional de trabajar en cualquier shell POSIX (como el guión).

a=$((2 - 2))
Gilles 'SO- deja de ser malvado'
fuente
1

Úselo en $(( $C - $D ))cambio para su aritmética. También es más eficiente.

tylerl
fuente
¿Qué lo hace más eficiente que decir (( A = $C - $D ))?
obispo
1

Yo tenía el mismo problema . tl; dr:

Si el último ARG [de let] se evalúa a 0, let devuelve 1; let devuelve 0 de lo contrario.

l0b0
fuente
1

Esta sintaxis funciona para mí:

a=$((b + c))
Mark Sawers
fuente