| 1 | # |
| 2 | # Test combination of var ops. |
| 3 | # |
| 4 | # NOTE: There are also slice tests in {array,arith-context}.test.sh. |
| 5 | |
| 6 | #### String slice |
| 7 | foo=abcdefg |
| 8 | echo ${foo:1:3} |
| 9 | ## STDOUT: |
| 10 | bcd |
| 11 | ## END |
| 12 | |
| 13 | #### Cannot take length of substring slice |
| 14 | # These are runtime errors, but we could make them parse time errors. |
| 15 | v=abcde |
| 16 | echo ${#v:1:3} |
| 17 | ## status: 1 |
| 18 | ## OK osh status: 2 |
| 19 | # zsh actually implements this! |
| 20 | ## OK zsh stdout: 3 |
| 21 | ## OK zsh status: 0 |
| 22 | |
| 23 | #### Out of range string slice: begin |
| 24 | # out of range begin doesn't raise error in bash, but in mksh it skips the |
| 25 | # whole thing! |
| 26 | foo=abcdefg |
| 27 | echo _${foo:100:3} |
| 28 | echo $? |
| 29 | ## STDOUT: |
| 30 | _ |
| 31 | 0 |
| 32 | ## END |
| 33 | ## BUG mksh stdout-json: "\n0\n" |
| 34 | |
| 35 | #### Out of range string slice: length |
| 36 | # OK in both bash and mksh |
| 37 | foo=abcdefg |
| 38 | echo _${foo:3:100} |
| 39 | echo $? |
| 40 | ## STDOUT: |
| 41 | _defg |
| 42 | 0 |
| 43 | ## END |
| 44 | ## BUG mksh stdout-json: "_defg\n0\n" |
| 45 | |
| 46 | #### Negative start index |
| 47 | foo=abcdefg |
| 48 | echo ${foo: -4:3} |
| 49 | ## stdout: def |
| 50 | |
| 51 | #### Negative start index respects unicode |
| 52 | foo=abcd-μ- |
| 53 | echo ${foo: -4:3} |
| 54 | ## stdout: d-μ |
| 55 | ## BUG mksh stdout: -μ |
| 56 | |
| 57 | #### Negative second arg is position, not length! |
| 58 | foo=abcdefg |
| 59 | echo ${foo:3:-1} ${foo: 3: -2} ${foo:3 :-3 } |
| 60 | ## stdout: def de d |
| 61 | ## BUG mksh stdout: defg defg defg |
| 62 | |
| 63 | #### Negative start index respects unicode |
| 64 | foo=abcd-μ- |
| 65 | echo ${foo: -5: -3} |
| 66 | ## stdout: cd |
| 67 | ## BUG mksh stdout: d-μ- |
| 68 | |
| 69 | #### String slice with math |
| 70 | # I think this is the $(()) language inside? |
| 71 | i=1 |
| 72 | foo=abcdefg |
| 73 | echo ${foo: i+4-2 : i + 2} |
| 74 | ## stdout: def |
| 75 | |
| 76 | #### Slice undefined |
| 77 | echo -${undef:1:2}- |
| 78 | set -o nounset |
| 79 | echo -${undef:1:2}- |
| 80 | echo -done- |
| 81 | ## STDOUT: |
| 82 | -- |
| 83 | ## END |
| 84 | ## status: 1 |
| 85 | # mksh doesn't respect nounset! |
| 86 | ## BUG mksh status: 0 |
| 87 | ## BUG mksh STDOUT: |
| 88 | -- |
| 89 | -- |
| 90 | -done- |
| 91 | ## END |
| 92 | |
| 93 | #### Slice UTF-8 String |
| 94 | # mksh slices by bytes. |
| 95 | foo='--μ--' |
| 96 | echo ${foo:1:3} |
| 97 | ## stdout: -μ- |
| 98 | ## BUG mksh stdout: -μ |
| 99 | |
| 100 | #### Slice string with invalid UTF-8 results in empty string and warning |
| 101 | s=$(echo -e "\xFF")bcdef |
| 102 | echo -${s:1:3}- |
| 103 | ## status: 0 |
| 104 | ## STDOUT: |
| 105 | -- |
| 106 | ## END |
| 107 | ## STDERR: |
| 108 | [??? no location ???] warning: Invalid start of UTF-8 character |
| 109 | ## END |
| 110 | ## BUG bash/mksh/zsh status: 0 |
| 111 | ## BUG bash/mksh/zsh STDOUT: |
| 112 | -bcd- |
| 113 | ## END |
| 114 | ## BUG bash/mksh/zsh stderr-json: "" |
| 115 | |
| 116 | |
| 117 | #### Slice string with invalid UTF-8 with strict_word_eval |
| 118 | shopt -s strict_word_eval || true |
| 119 | echo slice |
| 120 | s=$(echo -e "\xFF")bcdef |
| 121 | echo -${s:1:3}- |
| 122 | ## status: 1 |
| 123 | ## STDOUT: |
| 124 | slice |
| 125 | ## END |
| 126 | ## N-I bash/mksh/zsh status: 0 |
| 127 | ## N-I bash/mksh/zsh STDOUT: |
| 128 | slice |
| 129 | -bcd- |
| 130 | ## END |
| 131 | |
| 132 | #### Slice with an index that's an array itself not allowed |
| 133 | i=(3 4 5) |
| 134 | mystr=abcdefg |
| 135 | echo assigned |
| 136 | echo ${mystr:$i:2} |
| 137 | ## status: 1 |
| 138 | ## STDOUT: |
| 139 | assigned |
| 140 | ## END |
| 141 | ## BUG mksh/bash status: 0 |
| 142 | ## BUG mksh/bash STDOUT: |
| 143 | assigned |
| 144 | de |
| 145 | ## END |
| 146 | |
| 147 | #### Slice with an assoc array |
| 148 | declare -A A=(['5']=3 ['6']=4) |
| 149 | mystr=abcdefg |
| 150 | echo assigned |
| 151 | echo ${mystr:$A:2} |
| 152 | ## status: 1 |
| 153 | ## STDOUT: |
| 154 | assigned |
| 155 | ## END |
| 156 | ## N-I mksh stdout-json: "" |
| 157 | ## BUG bash/zsh status: 0 |
| 158 | ## BUG bash/zsh STDOUT: |
| 159 | assigned |
| 160 | ab |
| 161 | ## END |
| 162 | |
| 163 | #### Simple ${@:offset} |
| 164 | |
| 165 | set -- 4 5 6 |
| 166 | result=$(argv.py ${@:0}) |
| 167 | echo ${result//"$0"/'SHELL'} |
| 168 | argv.py ${@:1} |
| 169 | argv.py ${@:2} |
| 170 | ## STDOUT: |
| 171 | ['SHELL', '4', '5', '6'] |
| 172 | ['4', '5', '6'] |
| 173 | ['5', '6'] |
| 174 | ## END |
| 175 | ## N-I mksh status: 1 |
| 176 | ## N-I mksh stdout-json: "\n" |
| 177 | |
| 178 | |
| 179 | #### ${@:offset} and ${*:offset} |
| 180 | case $SH in (zsh) return ;; esac # zsh is very different |
| 181 | |
| 182 | argv.shell-name-checked () { |
| 183 | argv.py "${@//$0/SHELL}" |
| 184 | } |
| 185 | fun() { |
| 186 | argv.shell-name-checked -${*:0}- # include $0 |
| 187 | argv.shell-name-checked -${*:1}- # from $1 |
| 188 | argv.shell-name-checked -${*:3}- # last parameter $3 |
| 189 | argv.shell-name-checked -${*:4}- # empty |
| 190 | argv.shell-name-checked -${*:5}- # out of boundary |
| 191 | argv.shell-name-checked -${@:0}- |
| 192 | argv.shell-name-checked -${@:1}- |
| 193 | argv.shell-name-checked -${@:3}- |
| 194 | argv.shell-name-checked -${@:4}- |
| 195 | argv.shell-name-checked -${@:5}- |
| 196 | argv.shell-name-checked "-${*:0}-" |
| 197 | argv.shell-name-checked "-${*:1}-" |
| 198 | argv.shell-name-checked "-${*:3}-" |
| 199 | argv.shell-name-checked "-${*:4}-" |
| 200 | argv.shell-name-checked "-${*:5}-" |
| 201 | argv.shell-name-checked "-${@:0}-" |
| 202 | argv.shell-name-checked "-${@:1}-" |
| 203 | argv.shell-name-checked "-${@:3}-" |
| 204 | argv.shell-name-checked "-${@:4}-" |
| 205 | argv.shell-name-checked "-${@:5}-" |
| 206 | } |
| 207 | fun "a 1" "b 2" "c 3" |
| 208 | ## STDOUT: |
| 209 | ['-SHELL', 'a', '1', 'b', '2', 'c', '3-'] |
| 210 | ['-a', '1', 'b', '2', 'c', '3-'] |
| 211 | ['-c', '3-'] |
| 212 | ['--'] |
| 213 | ['--'] |
| 214 | ['-SHELL', 'a', '1', 'b', '2', 'c', '3-'] |
| 215 | ['-a', '1', 'b', '2', 'c', '3-'] |
| 216 | ['-c', '3-'] |
| 217 | ['--'] |
| 218 | ['--'] |
| 219 | ['-SHELL a 1 b 2 c 3-'] |
| 220 | ['-a 1 b 2 c 3-'] |
| 221 | ['-c 3-'] |
| 222 | ['--'] |
| 223 | ['--'] |
| 224 | ['-SHELL', 'a 1', 'b 2', 'c 3-'] |
| 225 | ['-a 1', 'b 2', 'c 3-'] |
| 226 | ['-c 3-'] |
| 227 | ['--'] |
| 228 | ['--'] |
| 229 | ## END |
| 230 | ## N-I mksh status: 1 |
| 231 | ## N-I mksh stdout-json: "" |
| 232 | ## BUG zsh stdout-json: "" |
| 233 | |
| 234 | #### ${@:offset:length} and ${*:offset:length} |
| 235 | case $SH in (zsh) return ;; esac # zsh is very different |
| 236 | |
| 237 | argv.shell-name-checked () { |
| 238 | argv.py "${@//$0/SHELL}" |
| 239 | } |
| 240 | fun() { |
| 241 | argv.shell-name-checked -${*:0:2}- # include $0 |
| 242 | argv.shell-name-checked -${*:1:2}- # from $1 |
| 243 | argv.shell-name-checked -${*:3:2}- # last parameter $3 |
| 244 | argv.shell-name-checked -${*:4:2}- # empty |
| 245 | argv.shell-name-checked -${*:5:2}- # out of boundary |
| 246 | argv.shell-name-checked -${@:0:2}- |
| 247 | argv.shell-name-checked -${@:1:2}- |
| 248 | argv.shell-name-checked -${@:3:2}- |
| 249 | argv.shell-name-checked -${@:4:2}- |
| 250 | argv.shell-name-checked -${@:5:2}- |
| 251 | argv.shell-name-checked "-${*:0:2}-" |
| 252 | argv.shell-name-checked "-${*:1:2}-" |
| 253 | argv.shell-name-checked "-${*:3:2}-" |
| 254 | argv.shell-name-checked "-${*:4:2}-" |
| 255 | argv.shell-name-checked "-${*:5:2}-" |
| 256 | argv.shell-name-checked "-${@:0:2}-" |
| 257 | argv.shell-name-checked "-${@:1:2}-" |
| 258 | argv.shell-name-checked "-${@:3:2}-" |
| 259 | argv.shell-name-checked "-${@:4:2}-" |
| 260 | argv.shell-name-checked "-${@:5:2}-" |
| 261 | } |
| 262 | fun "a 1" "b 2" "c 3" |
| 263 | ## STDOUT: |
| 264 | ['-SHELL', 'a', '1-'] |
| 265 | ['-a', '1', 'b', '2-'] |
| 266 | ['-c', '3-'] |
| 267 | ['--'] |
| 268 | ['--'] |
| 269 | ['-SHELL', 'a', '1-'] |
| 270 | ['-a', '1', 'b', '2-'] |
| 271 | ['-c', '3-'] |
| 272 | ['--'] |
| 273 | ['--'] |
| 274 | ['-SHELL a 1-'] |
| 275 | ['-a 1 b 2-'] |
| 276 | ['-c 3-'] |
| 277 | ['--'] |
| 278 | ['--'] |
| 279 | ['-SHELL', 'a 1-'] |
| 280 | ['-a 1', 'b 2-'] |
| 281 | ['-c 3-'] |
| 282 | ['--'] |
| 283 | ['--'] |
| 284 | ## END |
| 285 | ## N-I mksh status: 1 |
| 286 | ## N-I mksh stdout-json: "" |
| 287 | ## BUG zsh stdout-json: "" |
| 288 | |
| 289 | #### ${@:0:1} |
| 290 | set a b c |
| 291 | result=$(echo ${@:0:1}) |
| 292 | echo ${result//"$0"/'SHELL'} |
| 293 | ## STDOUT: |
| 294 | SHELL |
| 295 | ## END |
| 296 | ## N-I mksh stdout-json: "\n" |
| 297 | |
| 298 | #### ${array[@]::0} |
| 299 | array=(1 2 3) |
| 300 | argv.py ${array[@]::0} |
| 301 | ## STDOUT: |
| 302 | [] |
| 303 | ## END |
| 304 | ## N-I mksh/zsh status: 1 |
| 305 | ## N-I mksh/zsh stdout-json: "" |
| 306 | |
| 307 | #### ${array[@]::} |
| 308 | array=(1 2 3) |
| 309 | argv.py ${array[@]::} |
| 310 | ## STDOUT: |
| 311 | [] |
| 312 | ## END |
| 313 | ## N-I mksh/zsh status: 1 |
| 314 | ## N-I mksh/zsh status: 1 |
| 315 | ## N-I mksh/zsh stdout-json: "" |