LINUX.ORG.RU

bash: set -e и арифметические выражения

 


0

1

Доброго утра.

Допустим, у меня есть код со следующей арифметической операцией:

(( TOKEN_COUNTER++ ))

При включенном set -e этот код совершенно правомерно может завалить скрипт, поскольку здесь (( воспринимается как бы как команда; в свою очередь, эта команда при (( 0 )) возвращает 1, и именно это сваливает скрипт.

Это один из вариантов решения:

(( TOKEN_COUNTER++ )) || :

Но, может быть, есть что-нибудь, что можно использовать, не вдаваясь в подробности насчёт того, является ли (( какой-то там встроенной командой и возвращает ли она что-то там при определённых условиях? Хочется чего-то такого:

do_it_carefree (( TOKEN_COUNTER++ ))

Как это сделано в выражениях вроде if, while, until - и им подобных. В них и инкремент к переменной можно сделать, и отрицательный код возврата не валит скрипт, а останавливает выполнение кода под выражением.

Я было подумал про let, но это оказалось тем же самым, что и ((:

((expression))
              The expression is evaluated according to the rules described below under ARITHMETIC EVALUATION.  If the value of the expression is non-zero, the return status is 0; otherwise the return status is 1.  This is
              exactly equivalent to let «expression».

Алсо, есть ещё непонятки с вариантами стрельбы по ногам с включенной обработкой нештатных ситуаций.

$ a() { return 1; }
$ : $(a); echo $?
0
$ b=$(a); echo $?
1

Может быть, вы можете что-нибудь сказать на этот счёт, что прояснило бы как-то такое поведение, чтобы не оставаться просто так с опытом «так надо делать, а так - не стоит»?

ABW?

Ответ получен

★★

Последнее исправление: kalterfive (всего исправлений: 12)

Ответ на: комментарий от anonymous

и если задача позволяет, лучше попробовать писать на dash - он на порядок топорнее, напороться сложнее; с кодом возврата тоже есть проблемы, но поменьше

anonymous
()
Ответ на: комментарий от anonymous

А ключевой момент, на каком бы я сакцентировал внимание — совет товарища Вулиджа *не использовать* errexit.

Zmicier ★★★★★
()

Зачем решать выдуманные проблемы?

┌[legolegs@battlehummer ~/programing] :)
└> ./kalterfive.sh
Success. TOKEN_COUNTER=0
┌[legolegs@battlehummer ~/programing] :)
└> cat ./kalterfive.sh
#!/bin/bash

set -e

TOKEN_COUNTER=-1
(( TOKEN_COUNTER++ ))
echo Success. TOKEN_COUNTER=$TOKEN_COUNTER
legolegs ★★★★★
()
do_it_carefree(){ "$@" || :; }

carefree_let(){ let "$@" || :; }

do_it_carefree let TOKEN_COUNTER++

carefree_let TOKEN_COUNTER++

Да только, если честно, это такое же «вдавание в подробности».

NeXTSTEP ★★
()
Ответ на: комментарий от anonymous
#!/bin/bash -x
set -e

declare -i TOKEN_COUNTER=0
echo TOKEN_COUNTER=$TOKEN_COUNTER
TOKEN_COUNTER+=1
echo Success. TOKEN_COUNTER=$TOKEN_COUNTER

Целочисленная арифметика в BASH работает и без скобочек. Арифметики же нецелочисленной не было и не будет: матсопроцессор BASH'у не завезли :)

DRVTiny ★★★★★
()
Последнее исправление: DRVTiny (всего исправлений: 1)
Ответ на: комментарий от DRVTiny

Хм. Но можно привести и другой пример:

$ ./test-1.sh  

_="$(false)"

$ cat test-1.sh 
#!/usr/bin/bash -e

trap 'echo "$BASH_COMMAND"; exit' ERR

echo "$(false)"
_="$(false)"

Впрочем, наверное, это ничем и не стоит объяснять, потому что так всё и есть и с этим ничего не поделать.

kalterfive ★★
() автор топика
Последнее исправление: kalterfive (всего исправлений: 2)
Ответ на: комментарий от kalterfive

Точно так же работает сложение, вычитание, деление (деление в BASH, правда, по определению целочисленное, и это печально). Делаете «declare -i» или «local -i» - и можете даже «$» не указывать перед именами переменных.

DRVTiny ★★★★★
()
Ответ на: комментарий от kalterfive

BASH смотрит на код выполнения команды целиком, будь то сложение или echo.

Смотрите сами:

код выполнения : $(false) - УСПЕШНО

код выполнения _=«$(false)» - ОШИБКА

код выполнения echo «$(false)» - УСПЕШНО

У меня вылетает только на последней команде из 3-х:

#!/bin/bash
set -e

trap 'echo "command was executed: <<${BASH_COMMAND}>>" >&2; exit 1' ERR

: "$(false)"
echo "$(false)"
_="$(false)"

echo 'SUCCESS!'

DRVTiny ★★★★★
()
Ответ на: комментарий от DRVTiny

Гм. Я, наверное, чего-то не понимаю.

$ ./test.sh
./test.sh: line 4: TOKEN_COUNTER-=1: command not found

$ cat test.sh  
#!/usr/bin/bash -e

declare -i TOKEN_COUNTER=0
TOKEN_COUNTER-=1
echo "Success, TOKEN_COUNTER=$TOKEN_COUNTER"

kalterfive ★★
() автор топика
Ответ на: комментарий от kalterfive
TOKEN_COUNTER=TOKEN_COUNTER-1
TOKEN_COUNTER+=-1

К сожалению, так. «Вильк» и «тарельк» - без мягкого знака и женского рода. Это невозможно объяснить, это можно только запомнить :)

DRVTiny ★★★★★
()
Ответ на: комментарий от NeXTSTEP

Уж лучше

  clet () { let "${@}" '1' ; }
будет продолжать валиться на синтаксических ошибках.

ABW ★★★★★
()
Ответ на: комментарий от DRVTiny

все хорошо, молодец

только зачем ты отвечал на мой коммент? видно же что он контекстно-зависим

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.