name: "Arithmetic" cases: - name: "Empty expression" stdin: | echo $(()) - name: "Unquoted arithmetic" stdin: | echo $((1+1)) - name: "Arithmetic literals" stdin: | echo "$((0))" echo "$((1))" echo "$((10))" echo "$((010))" echo "$((0010))" echo "$((0x10))" echo "$((0x010))" - name: "Arithmetic literals with explicit bases" stdin: | echo "$((2#1010))" echo "$((8#16))" echo "$((16#faf))" echo "$((16#FAF))" echo "$((36#vvv))" echo "$((36#VVV))" # Base 37: A-Z map to 36-61 echo "$((37#a))" echo "$((37#a0))" echo "$((37#A))" # Base 62: a-z=10-35, A-Z=36-61 echo "$((62#A))" echo "$((62#a))" echo "$((62#Z))" echo "$((62#z))" # Base 63: @ = 62 echo "$((63#@))" echo "$((63#@9))" # Base 64: _ = 63 echo "$((64#_))" echo "$((64#@))" echo "$((64#_1))" echo "$((64#zzz))" - name: "Unary arithmetic operators with space" stdin: | echo "$(( - 1 ))" echo "$(( + 1 ))" echo "$(( ~ 10 ))" echo "$(( ! 10 ))" - name: "Parentheses" stdin: | echo "$(((10)))" echo "$((((10))))" echo "$(((((10)))))" echo "$(( (10) ))" echo "$(( (1+2) ))" echo "$(( (1 + 2) ))" echo "$(( ((1+2)) ))" echo "$(( ((1 + 2)) ))" echo "$(((1+2)*3))" echo "$(((1 + 2) * 3))" echo "$(( (1 + 2) * 3 ))" echo "$((((1+2)*3)))" echo "$(( ((1 + 2) * 3) ))" echo "$(( ( (1 + 2) * 3 ) ))" - name: "Basic quoted arithmetic" stdin: | echo " 1 + 1 == $((1+1))" echo " 2 * 3 == $((2*3))" echo " 9 / 3 == $((9/3))" echo "10 % 3 == $((10%3))" echo " 2 ** 3 == $((2**3))" echo " 2 | 4 == $((2|4))" echo " 2 & 4 == $((2&4))" echo " 2 ^ 3 == $((2^3))" echo " 1 && 1 == $((1&&1))" echo " 1 && 0 == $((1&&0))" echo " 1 || 0 == $((1||0))" echo " 0 || 1 == $((1||0))" echo " 1 , 2 == $((1,2))" - name: "Unary operators" stdin: | echo " -1 == $((-1))" echo " +1 == $((+1))" echo " ~10 == $((~10))" echo " !10 == $((!10))" - name: "Conditional operator" stdin: | echo "1 ? 2 : 3 == $((1?2:3))" echo "0 ? 2 : 3 == $((0?2:3))" - name: "Arithmetic with spacing" stdin: | echo $(( 75 + 68 )) - name: "Divide by zero" ignore_stderr: true stdin: | echo "1 / 0 == $((1/0))" echo "Result: $?" echo "1 % 0 == $((1%0))" echo "Result: $?" - name: "Shift arithmetic" stdin: | echo "32 >> 2 == $((32>>2))" echo " 1 << 4 == $((1<<4))" - name: Shift arithmetic in conditional" stdin: | (( 1 >> 1 )) && echo "1. true" (( 1 << 1 )) && echo "2. true" - name: "Variable references" stdin: | x=10 echo "x => $((x))" echo "x + 1 => $((x+1))" y= echo "y => $((y))" echo "y + 1 => $((y+1))" z=notnumber echo "z => $((z))" echo "z + 1 => $((z+1))" - name: "Complex variable references" stdin: | x=10 y=20 z=x+y a=z+z echo "z => $((z))" echo "a => $((a))" - name: "Nested expressions" stdin: | echo "1: $(($(echo -n 1; echo 2) + 37))" op="+" echo "2: $((10 ${op} 20))" expr="13 * 7" echo "3: $(($expr))" - name: "Assignment arithmetic" stdin: | x=0 echo "x = 1 => $((x = 1))" echo "x is now $x" echo "x += 3 => $((x += 3))" echo "x is now $x" echo "x -= 1 => $((x -= 1))" echo "x is now $x" echo "x *= 2 => $((x *= 2))" echo "x is now $x" echo "x++ == $((x++))" echo "x is now $x" echo "++x == $((++x))" echo "x is now $x" echo "x-- == $((x--))" echo "x is now $x" echo "--x == $((--x))" echo "x is now $x" echo "x |= 3 => $((x |= 3))" echo "x is now $x" echo "x &= 12 => $((x &= 12))" echo "x is now $x" echo "x %= 8 => $((x %= 8))" echo "x is now $x" echo "x ^= 7 => $((x ^= 7))" echo "x is now $x" - name: "Assignment with references" stdin: | x=10+3 echo "y = x => $((y = x))" echo "y is now $y" - name: "Assignments in logical boolean expressions" stdin: | x=0 echo "0 && x+=1 => $(( 0 && (x+=1) ))" echo "x: $x" x=0 echo "1 && x+=1 => $(( 1 && (x+=1) ))" echo "x: $x" x=0 echo "0 || x+=1 => $(( 0 || (x+=1) ))" echo "x: $x" x=0 echo "1 || x+=1 => $(( 1 || (x+=1) ))" echo "x: $x" - name: "Array arithmetic" stdin: | a=(1 2 3) declare -p a echo "a[0]: $((a[0]))" echo "a[2]: $((a[2]))" echo "a[3]: $((a[3]))" echo "b[2]: $((b[2]))" echo "a[1]=4 => $((a[1]=4))" echo "a[1]: $((a[1]))" echo "a[1]+=1 => $((a[1]+=1))" echo "a[1]: $((a[1]))" echo "c[1] += 3 => $((c[1] += 3))" - name: "Basic arithmetic comparison" stdin: | echo "0 < 1: $((0 < 1))" echo "0 <= 1: $((0 <= 1))" echo "0 == 1: $((0 == 1))" echo "0 != 1: $((0 != 1))" echo "0 > 1: $((0 > 1))" echo "0 >= 1: $((0 >= 1))" echo "0 < 0: $((0 < 0))" echo "0 <= 0: $((0 <= 0))" echo "0 == 0: $((0 == 0))" echo "0 != 0: $((0 != 0))" echo "0 > 0: $((0 > 0))" echo "0 >= 0: $((0 >= 0))" echo "1 < 0: $((1 < 0))" echo "1 <= 0: $((1 <= 0))" echo "1 == 0: $((1 == 0))" echo "1 != 0: $((1 != 0))" echo "1 > 0: $((1 > 0))" echo "1 >= 0: $((1 >= 0))" - name: "Legacy bracket arithmetic syntax" stdin: | x=5 x=$[x + 1] echo "x after increment: $x" echo "Direct: $[1 + 2]" - name: "Legacy bracket arithmetic in extended test" stdin: | number=4 [[ $[number % 2] == 0 ]] && echo "even" || echo "odd" number=5 [[ $[number % 2] == 0 ]] && echo "even" || echo "odd" - name: "Legacy bracket arithmetic in double-quoted string" stdin: | echo "Quoted: result: $[2 * 3]" - name: "Legacy bracket arithmetic complex expression" stdin: | echo "Complex: $[1 + 2 * 3 - 4 / 2 % 2]" - name: "Legacy bracket arithmetic with array subscript" stdin: | arr=(10 20 30) echo "Array elem: $[arr[1] + 5]" - name: "Prefix increment/decrement with space before lvalue" stdin: | x=5 echo "++ x => $(( ++ x ))" echo "x is now $x" echo "-- x => $(( -- x ))" echo "x is now $x" # Also test in (( )) command form y=10 (( ++ y )) echo "y after ++ y: $y" (( -- y )) echo "y after -- y: $y" - name: "INT64_MIN and wrapping arithmetic" stdin: | # INT64_MIN via unary minus of the literal echo "$(( -9223372036854775808 ))" # Wrapping negation of INT64_MIN echo "$(( - (-9223372036854775808) ))" # INT64_MIN % -1 should be 0 (not crash) echo "$(( (-9223372036854775808) % (-1) ))" # INT64_MIN / -1 wraps echo "$(( (-9223372036854775808) / (-1) ))" # Wrapping increment/decrement near boundaries echo "$(( 9223372036854775807 + 1 ))" # wraps to INT64_MIN - name: "Non-cyclic variable dereference chain" stdin: | a=b b=c c=42 echo "$((a))" - name: "Self-referencing variable in arithmetic" ignore_stderr: true stdin: | a=a echo "$(( a ))" echo "exit: $?" - name: "Recursive variable evaluation with depth limit" ignore_stderr: true stdin: | # Recursive variables should not cause stack overflow a=b b=a echo "$(( a ))" echo "exit: $?" - name: "Arithmetic with nameref variable" known_failure: true stdin: | counter=10 declare -n ref=counter echo "before: $counter" (( ref++ )) echo "after ++: $counter" (( ref += 5 )) echo "after +=5: $counter" echo "expr: $(( ref * 2 ))"