bash -e se ferme lorsque let ou expr est évalué à 0

19

J'ai un script bash qui définit -e afin que le script se termine sur n'importe quel état de sortie! = 0.

J'essaie de faire une arithmétique de base du shell affectée aux variables et parfois l'expression est égale à 0, ce qui fait que l'état de sortie de la commande let ou expr est "1".

Voici un exemple:

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

La sortie est:

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

Ma question est quelle est la manière idiomatique de script bash pour permettre au script d'échouer sur de vraies erreurs de sortie et non sur une arithmétique de base égale à 0. Je pourrais suffixer toutes ces expressions avec:

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

Mais cela semble bizarre.

Dougnukem
la source

Réponses:

16

Ne pas utiliser exprpour l'arithmétique. Il est depuis longtemps obsolète: les shells ont maintenant une arithmétique intégrée, avec la $((…))construction (POSIX), ou avec la letconstruction (ksh / bash / zsh) ou la ((…))construction (ksh / bash / zsh).

letet ((…))renvoyez 1 (un code d'état d'échec) si la dernière expression évaluée est 0. Pour éviter que cela ne provoque la fermeture de votre script sous set -e, faites en sorte que la dernière expression ne renvoie pas 0, par exemple:

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

Vous pouvez également utiliser l' || trueidiome:

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

Sinon, faites votre arithmétique à l'intérieur $((…))et vos tâches à l'extérieur. Une affectation renvoie l'état de la dernière substitution de commande dans la valeur, ou 0 s'il n'y a pas de substitution de commande, donc vous êtes en sécurité. Cela a l'avantage supplémentaire de fonctionner dans n'importe quel shell POSIX (tel qu'un tiret).

a=$((2 - 2))
Gilles 'SO- arrête d'être méchant'
la source
1

Utilisez $(( $C - $D ))plutôt pour votre arithmatique. C'est aussi plus efficace.

tylerl
la source
Qu'est-ce qui le rend plus efficace que dire (( A = $C - $D ))?
évêque le
1

J'ai eu le même problème . tl; dr:

Si le dernier ARG [de let] est évalué à 0, let renvoie 1; laissez renvoie 0 sinon.

l0b0
la source
1

Cette syntaxe fonctionne pour moi:

a=$((b + c))
Mark Sawers
la source