bash -e выходит, когда значение let или expr равно 0

19

У меня есть скрипт bash, который устанавливает -e, поэтому скрипт будет завершаться при любом состоянии выхода! = 0.

Я пытаюсь сделать некоторую базовую арифметику оболочки, назначенную для переменных, и иногда выражение равно 0, что приводит к состоянию выхода команды let или expr, равному «1».

Вот пример:

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

Выход:

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

Мой вопрос заключается в том, каков идиоматический способ написания сценариев bash, позволяющий скрипту давать сбой при реальных ошибках выхода, а не при базовой арифметике, равной 0. Я мог бы суффиксить все эти выражения с помощью:

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

Но это кажется вздорным.

Dougnukem
источник

Ответы:

16

Не используйте exprдля арифметики. Он уже давно устарел: в оболочку встроена арифметика с помощью $((…))конструкции (POSIX) или letвстроенной (ksh / bash / zsh) или ((…))конструкции (ksh / bash / zsh).

letи ((…))верните 1 (код состояния ошибки), если последнее оцененное выражение равно 0. Чтобы избежать этого из-за того, что ваш скрипт завершил работу set -e, организуйте, чтобы последнее выражение не возвращало 0, например:

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

В качестве альтернативы используйте || trueидиому:

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

В качестве альтернативы, сделайте свою арифметику внутри $((…))и свои задания снаружи. Присвоение возвращает статус последней подстановки команды в значении или 0, если подстановка команды отсутствует, так что вы в безопасности. Это дает дополнительное преимущество работы в любой оболочке POSIX (например, dash).

a=$((2 - 2))
Жиль "ТАК - прекрати быть злым"
источник
1

Используйте $(( $C - $D ))вместо этого для своей арифметики. Это также более эффективно.

tylerl
источник
Что делает это более эффективным, чем сказать (( A = $C - $D ))?
епископ
1

У меня была такая же проблема . ТЛ; др:

Если последний ARG [of let] оценивается как 0, let возвращает 1; пусть возвращает 0 в противном случае.

l0b0
источник
1

Этот синтаксис работает для меня:

a=$((b + c))
Марк Сойерс
источник