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

16

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

Estou tentando fazer alguma aritmética de shell básica 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".

Veja 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 idiomática de script bash para permitir que o script falhe em erros de saída reais e não em aritmética básica igual a 0. Eu poderia sufocar todas as expressões com:

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

Mas isso parece hacky.

    
por Dougnukem 31.01.2013 / 00:44

4 respostas

14

Não use expr para aritmética. Há muito tempo está obsoleto: os shells agora possuem aritmética integrada, com a construção $((…)) (POSIX) ou com let builtin (ksh / bash / zsh) ou a construção ((…)) (ksh / bash / zsh).

let e ((…)) return 1 (um código de status de falha) se a última expressão avaliada for 0. Para evitar que esse script saia em set -e , organize a última expressão para não retornar 0, para exemplo:

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

Como alternativa, use o || true idiom:

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

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

a=$((2 - 2))
    
por 01.02.2013 / 00:47
1

Use $(( $C - $D )) para sua aritmética. É mais eficiente também.

    
por 31.01.2013 / 03:49
1

Eu tinha o mesmo problema . tl; dr:

If the last ARG [of let] evaluates to 0, let returns 1; let returns 0 otherwise.

    
por 31.01.2013 / 10:55
0

Esta sintaxe funciona para mim:

a=$((b + c))
    
por 19.10.2018 / 16:50