bash -e sai quando let ou expr é avaliado como 0

19

Eu tenho um script bash que define -e, para que o script saia em qualquer status de saída! = 0.

Estou tentando fazer uma aritmética básica de shell atribuída a variáveis ​​e, às vezes, a expressão é igual a 0, o que faz com que o status de saída do comando let ou expr seja "1".

Aqui está um exemplo:

#!/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"

A saída é:

$ ./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'

Minha pergunta é qual é a maneira de script idiomático do bash para permitir que o script falhe em erros de saída reais e não na aritmética básica igual a 0. Eu poderia sufocar todas essas expressões com:

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

Mas isso parece hacky.

Dougnukem
fonte

Respostas:

16

Não use exprpara aritmética. Há muito tempo está obsoleto: os shells agora têm aritmética embutida, com a $((…))construção (POSIX) ou com a construção let(ksh / bash / zsh) ou a ((…))construção (ksh / bash / zsh).

lete ((…))retorne 1 (um código de status de falha) se a última expressão avaliada for 0. Para evitar que isso faça com que seu script saia abaixo set -e, organize a última expressão para não retornar 0, por exemplo:

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

Como alternativa, use o || trueidioma:

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

Como alternativa, faça sua aritmética interna $((…))e suas atribuições externas. Uma atribuição retorna o status da última substituição de comando no valor, ou 0 se não houver substituição de comando, para que você esteja seguro. Isso tem o benefício adicional de trabalhar em qualquer shell POSIX (como traço).

a=$((2 - 2))
Gilles 'SO- parar de ser mau'
fonte
1

Use em $(( $C - $D ))vez disso para o seu aritmético. Também é mais eficiente.

tylerl
fonte
O que o torna mais eficiente do que dizer (( A = $C - $D ))?
bispo
1

Eu tive o mesmo problema . tl; dr:

Se o último ARG [de let] for avaliado como 0, let retornará 1; let retorna 0 caso contrário.

l0b0
fonte
1

Essa sintaxe funciona para mim:

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