Bash errexit with arithmetic expansion [duplicate] - bash

This question already has an answer here:
Why does ((count++)) return 1 exit code first time run
(1 answer)
Closed 5 years ago.
I have the following Bash script called errexit:
#! /bin/bash
set -ex
a=$1
((a++))
echo $a
When I run it with the argument "0", it triggers the error exit:
$ ./errexit 0; echo $?
+ a=0
+ (( a++ ))
1
But when I run it with the argument "1", it does not trigger the error exit:
$ ./errexit 1; echo $?
+ a=1
+ (( a++ ))
+ echo 2
2
0
I do not understand, why 2 is not interpreted as false, although it is the case in an if statement:
$ if grep nix nix; then echo $?=t; else echo $?=f; fi
grep: nix: No such file or directory
2=f
Can anybody explain why the arithmetic expansion behaves differently?

According to the Bash manual:
((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".
So according to the post-operator. The value of ((a++)) when a=0 is 0. So the return status is 1.
a=0
echo $((a++)) # 0

Related

decrement the variable value by 1 in shell

what is the correct syntax to decrement/decrease the variable value by 1 in while loop using /bin/sh and not using /bin/bash script
I used following but does not work
a=15
((a=a-1)) // not working
((a--)) // not working
EDIT 1
i=0
a=[]
b=15
while [ $a == [] ] && [ "$i" -le 15 ]
do
echo " Waiting ."
sleep 60s
((i=i+1))
b=`expr $b- 1`
a=`some command`
done
still getting following error
sh: was: unknown operand /bin/sh: exit: line 186: Illegal number: -1
Arithmetic substitution is spelled $(( )) and expands to the result. If you just need the side effect (e.g. increment), use it in a null command:
a=15
: $((--a))
echo $a
Note that shell arithmetic is integer only.
$ a=15
$ a=`expr $a - 1`
$ echo $a
14

Why does bash post-increment operator set a nonzero result code? [duplicate]

This question already has answers here:
Bash exit status of shorthand increment notation
(2 answers)
Why does ((count++)) return 1 exit code first time run
(1 answer)
Closed 1 year ago.
This caught me by surprise: applying the post-increment operator
(++) to a zero value variable results in a non-zero result code.
That is, given:
#!/bin/bash
myvar=0
let myvar++
echo "result: $?"
Running that (with bash 5.1.0) results in:
result: 1
Why does that produce a nonzero result code? We see the same behavior
using a numeric expression:
#!/bin/bash
myvar=0
(( myvar++ ))
echo "result: $?"
On the other hand, if we use += instead of ++, or if we start with
a nonzero value of myvar, we receive a 0 result code as expected. The
following...
myvar=1
let myvar+=1
echo "result: $?"
myvar=1
let myvar++
echo "result: $?"
myvar=1
(( myvar++ ))
echo "result: $?"
...all produce:
result: 0
What's going on here?
From the bash man page, in the section describing let:
Each arg is an arithmetic expression to be evaluated (see ARITHMETIC EVALUATION). If the last arg evaluates to 0, let returns 1; 0 is returned otherwise
It's not the operator that establishes the value of $?, it is let. Since the value of the argument to let in the command let myvar++ is 0, let returns 1.
For post-increment expressions, bash evaluates the variable and sets the result code before applying the increment. In each case where the value before the post-increment was 0, it follows the documented behavior,
If the last arg evaluates to 0, let returns 1; 0 is returned otherwise.
Note the difference if you use pre-increment,
myvar=0
let ++myvar
echo "result: $?"
>> result: 0
In exp0() in https://git.savannah.gnu.org/cgit/bash.git/tree/expr.c#n1014 , for PREINC it binds the (stringifed) value of v2 then assigns it to val, but under POSTINC it binds the variable then discards v2 without assigning it to val.

syntax error: unexpected end of file trying to run a simple bash script

I really can't see what the issue is with my script is. I've considered missing quotations or other syntax errors. There's got to be something I'm missing. It's a very simple while loop script...
#!/bin/bash
c=1
while [ $c -le 5 ]
do
echo "Welcone $c times"
c=$(( c++ ))
done
I should mention that I'm running bash in cygwin on windows 7.
thanks for the help
Change:
c=$(( c++ ))
to
(( c=c+1 ))
When Bash sees: (( var)) it will try and 'do some math' on contents... In this case 'c++' == empty string == '0'; c will always be equal to '1' due to 1st assignment...
From the Bash man page on my Linux system (you may need to review this for Cygwin - could be different...):
((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".
Also:
id++ id--
variable post-increment and post-decrement
++id --id
variable pre-increment and pre-decrement
After a little testing, the 'pre-increment' seems to do what you are after here - note that you may need to declare 'c' as an integer:
typeset -i c=1
while [ $c -le 5 ]
do
echo "Welcone $c times"
c=++c
# (( c=c+1 ))
done

Why b doesn't change always its value when I run ((a++)) && ((b++)) in bash?

Let's take the following example from my terminal:
$ a=0 && b=1
$ echo $a $b
0 1
$ # Everything OK
$ ((a++)) && ((b++))
$ echo $a $b
1 1
$ # What? Why only a changed its value and b no?
$ ((a++)) && ((b++))
$ echo $a $b
2 2
$ # Now the value of b has changed...
Can someone to make me understand why this is happening?
a++ is post-increment, i.e. the increment happens after the value is tested.
The test on a fails because a is zero at the time it is tested.
&& is the logical AND operator. If its first argument is false, it doesn't bother evaluating the second. This is called "short-circuiting" and saves processing time.
Since ++ is post increment, if a is zero when evaluating ((a++)) && ((b++)), it evaluates a first, gets zero (which is false), adds 1 to a, then quits due to the short-circuit without evaluating the second part. So b does not get incremented.
((a++)) increments the value of $a in 1. Its exit status $? is 0 if the evaluated expression was not 0 and 1 otherwise. If its exit status is, than, because of && the second command - ((b++)) - will not run.
As man bash indicates, if the value of the expression is non-zero, the return status is 0; otherwise the return status is 1. As per a++ being a post-increment expression, the expression evaluates $a itself and then increments its value, so that the return status of ((a++)) will be 0 when the expression is non-zero, and 1 otherwise.
So, counter-intuitively:
when $a is unset, the return status will be 1.
when $a is a string, the return status will be 1.
when $a is equal to 0, the return status will be 1.
when $a is set to a number different from 0, the return status will be 0.
See an example:
The variable is 0.
$ t=0
We perform ((t++)) and see what the command is returning with the echo $( command ) expression:
$ echo $(((t++)))
0
But note that the value of $t has been incremented.
$ echo $t
1
The same if we do it again:
$ echo $(((t++)))
1
$ echo $t
2
$ echo $(((t++)))
2
$ echo $t
3
See man bash:
((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".
When a is 0, the value of ((a++)) is interpreted as not true.

Bash exit status of shorthand increment notation

I noticed an apparent inconsistency in the return status of bash's (( )) notation.
Consider the following
$> A=0
$> ((A=A+1))
$> echo $? $A
0 1
However using the other well known shorthand increment notation yields:
$> A=0
$> ((A++))
$> echo $? $A
1 1
If one has the builtin set -e in the script the second notation will cause the script to exit, since the exit status of the ((A++)) returned non-zero. This question was more or less addressed in this related question. But it does not seem to explain the difference in exit status for the two notations ((A=A+1)) and ((A++))
((A++)) seems to return 1 if and only if A equals 0. (Disclaimer: I have not done exhaustive tests. Tested in bash 4.1.2 and 4.2.25). So the final question boils down to:
Why does A=0; ((A++)) return 1?
a++ is post-increment: it increments after the statement is evaluated. By contrast, ++a increments before. Thus:
$ a=0 ; ((a++)) ; echo $a $?
1 1
$ a=0 ; ((++a)) ; echo $a $?
1 0
In the first case, ((a++)), the arithmetic expression is evaluated first, while a is still zero, yielding a value of zero (and hence a nonzero return status). Then, afterward, a is incremented.
In second case, ((++a)), a is incremented to 1 and then ((...)) is evaluated. Since a is nonzero when the arithmetic expression is evaluated, the return status is zero.
From man bash:
id++ id--
variable post-increment and post-decrement
++id --id
variable pre-increment and pre-decrement
The exit status of the (()) notation is zero if the arithmetic expression is nonzero, and vice versa.
A=A+1
You assign 1 to A, so the expression evaluates to 1, exit status zero.
A++
POST-increment operator. The expression evaluates to zero, exit status 1, and then A is incremented.

Resources