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
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
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.
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
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.
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.