1 #!/bin/bash
2 #
3 # Interesting interpretation of constants.
4 #
5 # "Constants with a leading 0 are interpreted as octal numbers. A leading ‘0x’
6 # or ‘0X’ denotes hexadecimal. Otherwise, numbers take the form [base#]n, where
7 # the optional base is a decimal number between 2 and 64 representing the
8 # arithmetic base, and n is a number in that base. If base# is omitted, then
9 # base 10 is used. When specifying n, the digits greater than 9 are represented
10 # by the lowercase letters, the uppercase letters, ‘@’, and ‘_’, in that order.
11 # If base is less than or equal to 36, lowercase and uppercase letters may be
12 # used interchangeably to represent numbers between 10 and 35. "
13 #
14 # NOTE $(( 8#9 )) can fail, and this can be done at parse time...
15
16 ### Add one to var
17 i=1
18 echo $(($i+1))
19 # stdout: 2
20
21 ### $ is optional
22 i=1
23 echo $((i+1))
24 # stdout: 2
25
26 ### Bizarre recursive evaluation rule
27 foo=5
28 bar=foo
29 spam=bar
30 eggs=spam
31 echo $((foo+1)) $((bar+1)) $((spam+1)) $((eggs+1))
32 # stdout: 6 6 6 6
33 # N-I dash stdout-json: ""
34 # N-I dash status: 2
35
36 ### Can use Braced VarSub within ArithSub
37 echo $((${j:-5} + 1))
38 # stdout: 6
39
40 ### Arith word part
41 foo=1; echo $((foo+1))bar$(($foo+1))
42 # stdout: 2bar2
43
44 ### Arith sub with word parts
45 # Making 13 from two different kinds of sub. Geez.
46 echo $((1 + $(echo 1)${undefined:-3}))
47 # stdout: 14
48
49 ### Constant with quotes like '1'
50 # NOTE: Compare with [[. That is a COMMAND level expression, while this is a
51 # WORD level expression.
52 echo $(('1' + 2))
53 # status: 0
54 # N-I bash/zsh status: 1
55 # N-I dash status: 2
56
57 ### Arith sub within arith sub
58 # This is unnecessary but works in all shells.
59 echo $((1 + $((2 + 3)) + 4))
60 # stdout: 10
61
62 ### Backticks within arith sub
63 # This is unnecessary but works in all shells.
64 echo $((`echo 1` + 2))
65 # stdout: 3
66
67 ### Bad variable substitution
68 # Hm bash, mksh, and zsh ignore the variable. They treat it as 0?
69 s=foo
70 echo $((s+5))
71 # status: 1
72 # OK dash status: 2
73 # BUG bash/mksh/zsh status: 0
74
75 ### Two bad variable substitutions
76 s=foo
77 t=bar
78 echo $((s+t))
79 # status: 1
80 # OK dash status: 2
81 # BUG bash/mksh/zsh status: 0
82
83 ### Newline in the middle of expression
84 echo $((1
85 + 2))
86 # stdout: 3
87
88 ### Ternary operator
89 a=1
90 b=2
91 echo $((a>b?5:10))
92 # stdout: 10
93
94 ### Preincrement
95 a=4
96 echo $((++a))
97 echo $a
98 # stdout-json: "5\n5\n"
99 # N-I dash status: 0
100 # N-I dash stdout-json: "4\n4\n"
101
102 ### Postincrement
103 a=4
104 echo $((a++))
105 echo $a
106 # stdout-json: "4\n5\n"
107 # N-I dash status: 2
108 # N-I dash stdout-json: ""
109
110 ### Comma operator (borrowed from C)
111 a=1
112 b=2
113 echo $((a,(b+1)))
114 # stdout: 3
115 # N-I dash status: 2
116 # N-I dash stdout-json: ""
117
118 ### Mutating ops
119 a=4
120 echo $((a+=1))
121 echo $a
122 # stdout-json: "5\n5\n"
123
124 ### Bitwise ops
125 echo $((1|2))
126 echo $((1&2))
127 echo $((~(1|2)))
128 # stdout-json: "3\n0\n-4\n"
129
130 ### Unary minus and plus
131 a=1
132 b=3
133 echo $((- a + + b))
134 # stdout-json: "2\n"
135
136 ### No floating point
137 echo $((1 + 2.3))
138 # status: 1
139 # OK dash status: 2
140 # BUG zsh status: 0
141
142 ### Array indexing in arith
143 # zsh does 1-based indexing!
144 array=(1 2 3 4)
145 echo $((array[1] + array[2]*3))
146 # stdout: 11
147 # OK zsh stdout: 7
148 # N-I dash status: 2
149 # N-I dash stdout-json: ""
150
151 ### Constants in base 36
152 echo $((36#a))-$((36#z))
153 # stdout: 10-35
154 # N-I dash stdout-json: ""
155 # N-I dash status: 2
156
157 ### Constants in bases 2 to 64
158 # This is a truly bizarre syntax. Oh it comes from zsh... which allows 36.
159 echo $((64#a))-$((64#z)), $((64#A))-$((64#Z)), $((64#@)), $(( 64#_ ))
160 # stdout: 10-35, 36-61, 62, 63
161 # N-I dash stdout-json: ""
162 # N-I dash status: 2
163 # N-I mksh/zsh stdout-json: ""
164 # N-I mksh/zsh status: 1
165
166 ### Dynamic base constants
167 base=16
168 echo $(( ${base}#a ))
169 # stdout: 10
170 # N-I dash stdout-json: ""
171 # N-I dash status: 2
172
173 ### Octal constant
174 echo $(( 011 ))
175 # stdout: 9
176 # N-I mksh/zsh stdout: 11
177
178 ### Dynamic octal constant
179 zero=0
180 echo $(( ${zero}11 ))
181 # stdout: 9
182 # N-I mksh/zsh stdout: 11
183
184 ### Dynamic hex constants
185 zero=0
186 echo $(( ${zero}xAB ))
187 # stdout: 171
188
189 ### Dynamic var names!
190 foo=5
191 x=oo
192 echo $(( foo + f$x + 1 ))
193 # stdout: 11