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