1 # Test combination of var ops.
2 #
3 # NOTE: There are also slice tests in {array,arith-context}.test.sh.
4
5 ## compare_shells: bash mksh zsh
6
7 #### String slice
8 foo=abcdefg
9 echo ${foo:1:3}
10 ## STDOUT:
11 bcd
12 ## END
13
14 #### Cannot take length of substring slice
15 # These are runtime errors, but we could make them parse time errors.
16 v=abcde
17 echo ${#v:1:3}
18 ## status: 1
19 ## OK osh status: 2
20 # zsh actually implements this!
21 ## OK zsh stdout: 3
22 ## OK zsh status: 0
23
24 #### Out of range string slice: begin
25 # out of range begin doesn't raise error in bash, but in mksh it skips the
26 # whole thing!
27 foo=abcdefg
28 echo _${foo:100:3}
29 echo $?
30 ## STDOUT:
31 _
32 0
33 ## END
34 ## BUG mksh stdout-json: "\n0\n"
35
36 #### Out of range string slice: length
37 # OK in both bash and mksh
38 foo=abcdefg
39 echo _${foo:3:100}
40 echo $?
41 ## STDOUT:
42 _defg
43 0
44 ## END
45 ## BUG mksh stdout-json: "_defg\n0\n"
46
47 #### Negative start index
48 foo=abcdefg
49 echo ${foo: -4:3}
50 ## stdout: def
51
52 #### Negative start index respects unicode
53 foo=abcd-μ-
54 echo ${foo: -4:3}
55 ## stdout: d-μ
56 ## BUG mksh stdout: -μ
57
58 #### Negative second arg is position, not length!
59 foo=abcdefg
60 echo ${foo:3:-1} ${foo: 3: -2} ${foo:3 :-3 }
61 ## stdout: def de d
62 ## BUG mksh stdout: defg defg defg
63
64 #### Negative start index respects unicode
65 foo=abcd-μ-
66 echo ${foo: -5: -3}
67 ## stdout: cd
68 ## BUG mksh stdout: d-μ-
69
70 #### String slice with math
71 # I think this is the $(()) language inside?
72 i=1
73 foo=abcdefg
74 echo ${foo: i+4-2 : i + 2}
75 ## stdout: def
76
77 #### Slice undefined
78 echo -${undef:1:2}-
79 set -o nounset
80 echo -${undef:1:2}-
81 echo -done-
82 ## STDOUT:
83 --
84 ## END
85 ## status: 1
86 # mksh doesn't respect nounset!
87 ## BUG mksh status: 0
88 ## BUG mksh STDOUT:
89 --
90 --
91 -done-
92 ## END
93
94 #### Slice UTF-8 String
95 # mksh slices by bytes.
96 foo='--μ--'
97 echo ${foo:1:3}
98 ## stdout: -μ-
99 ## BUG mksh stdout: -μ
100
101 #### Slice string with invalid UTF-8 results in empty string and warning
102 s=$(echo -e "\xFF")bcdef
103 echo -${s:1:3}-
104 ## status: 0
105 ## STDOUT:
106 --
107 ## END
108 ## STDERR:
109 [??? no location ???] warning: UTF-8 decode: Bad encoding at offset 0 in string of 6 bytes
110 ## END
111 ## BUG bash/mksh/zsh status: 0
112 ## BUG bash/mksh/zsh STDOUT:
113 -bcd-
114 ## END
115 ## BUG bash/mksh/zsh stderr-json: ""
116
117
118 #### Slice string with invalid UTF-8 with strict_word_eval
119 shopt -s strict_word_eval || true
120 echo slice
121 s=$(echo -e "\xFF")bcdef
122 echo -${s:1:3}-
123 ## status: 1
124 ## STDOUT:
125 slice
126 ## END
127 ## N-I bash/mksh/zsh status: 0
128 ## N-I bash/mksh/zsh STDOUT:
129 slice
130 -bcd-
131 ## END
132
133 #### Slice with an index that's an array -- silent a[0] decay
134 i=(3 4 5)
135 mystr=abcdefg
136 echo assigned
137 echo ${mystr:$i:2}
138
139 ## status: 0
140 ## STDOUT:
141 assigned
142 de
143 ## END
144 ## OK zsh status: 1
145 ## OK zsh STDOUT:
146 assigned
147 ## END
148
149 #### Slice with an assoc array
150 declare -A A=(['5']=3 ['6']=4)
151 mystr=abcdefg
152 echo assigned
153 echo ${mystr:$A:2}
154
155 ## status: 0
156 ## STDOUT:
157 assigned
158 ab
159 ## END
160
161 ## N-I mksh status: 1
162 ## N-I mksh stdout-json: ""
163
164 #### Simple ${@:offset}
165
166 set -- 4 5 6
167
168 result=$(argv.py ${@:0})
169 echo ${result//"$0"/'SHELL'}
170
171 argv.py ${@:1}
172 argv.py ${@:2}
173
174 ## STDOUT:
175 ['SHELL', '4', '5', '6']
176 ['4', '5', '6']
177 ['5', '6']
178 ## END
179 ## N-I mksh status: 1
180 ## N-I mksh stdout-json: "\n"
181
182
183 #### ${@:offset} and ${*:offset}
184 case $SH in (zsh) return ;; esac # zsh is very different
185
186 argv.shell-name-checked () {
187 argv.py "${@//$0/SHELL}"
188 }
189 fun() {
190 argv.shell-name-checked -${*:0}- # include $0
191 argv.shell-name-checked -${*:1}- # from $1
192 argv.shell-name-checked -${*:3}- # last parameter $3
193 argv.shell-name-checked -${*:4}- # empty
194 argv.shell-name-checked -${*:5}- # out of boundary
195 argv.shell-name-checked -${@:0}-
196 argv.shell-name-checked -${@:1}-
197 argv.shell-name-checked -${@:3}-
198 argv.shell-name-checked -${@:4}-
199 argv.shell-name-checked -${@:5}-
200 argv.shell-name-checked "-${*:0}-"
201 argv.shell-name-checked "-${*:1}-"
202 argv.shell-name-checked "-${*:3}-"
203 argv.shell-name-checked "-${*:4}-"
204 argv.shell-name-checked "-${*:5}-"
205 argv.shell-name-checked "-${@:0}-"
206 argv.shell-name-checked "-${@:1}-"
207 argv.shell-name-checked "-${@:3}-"
208 argv.shell-name-checked "-${@:4}-"
209 argv.shell-name-checked "-${@:5}-"
210 }
211 fun "a 1" "b 2" "c 3"
212 ## STDOUT:
213 ['-SHELL', 'a', '1', 'b', '2', 'c', '3-']
214 ['-a', '1', 'b', '2', 'c', '3-']
215 ['-c', '3-']
216 ['--']
217 ['--']
218 ['-SHELL', 'a', '1', 'b', '2', 'c', '3-']
219 ['-a', '1', 'b', '2', 'c', '3-']
220 ['-c', '3-']
221 ['--']
222 ['--']
223 ['-SHELL a 1 b 2 c 3-']
224 ['-a 1 b 2 c 3-']
225 ['-c 3-']
226 ['--']
227 ['--']
228 ['-SHELL', 'a 1', 'b 2', 'c 3-']
229 ['-a 1', 'b 2', 'c 3-']
230 ['-c 3-']
231 ['--']
232 ['--']
233 ## END
234 ## N-I mksh status: 1
235 ## N-I mksh stdout-json: ""
236 ## BUG zsh stdout-json: ""
237
238 #### ${@:offset:length} and ${*:offset:length}
239 case $SH in (zsh) return ;; esac # zsh is very different
240
241 argv.shell-name-checked () {
242 argv.py "${@//$0/SHELL}"
243 }
244 fun() {
245 argv.shell-name-checked -${*:0:2}- # include $0
246 argv.shell-name-checked -${*:1:2}- # from $1
247 argv.shell-name-checked -${*:3:2}- # last parameter $3
248 argv.shell-name-checked -${*:4:2}- # empty
249 argv.shell-name-checked -${*:5:2}- # out of boundary
250 argv.shell-name-checked -${@:0:2}-
251 argv.shell-name-checked -${@:1:2}-
252 argv.shell-name-checked -${@:3:2}-
253 argv.shell-name-checked -${@:4:2}-
254 argv.shell-name-checked -${@:5:2}-
255 argv.shell-name-checked "-${*:0:2}-"
256 argv.shell-name-checked "-${*:1:2}-"
257 argv.shell-name-checked "-${*:3:2}-"
258 argv.shell-name-checked "-${*:4:2}-"
259 argv.shell-name-checked "-${*:5:2}-"
260 argv.shell-name-checked "-${@:0:2}-"
261 argv.shell-name-checked "-${@:1:2}-"
262 argv.shell-name-checked "-${@:3:2}-"
263 argv.shell-name-checked "-${@:4:2}-"
264 argv.shell-name-checked "-${@:5:2}-"
265 }
266 fun "a 1" "b 2" "c 3"
267 ## STDOUT:
268 ['-SHELL', 'a', '1-']
269 ['-a', '1', 'b', '2-']
270 ['-c', '3-']
271 ['--']
272 ['--']
273 ['-SHELL', 'a', '1-']
274 ['-a', '1', 'b', '2-']
275 ['-c', '3-']
276 ['--']
277 ['--']
278 ['-SHELL a 1-']
279 ['-a 1 b 2-']
280 ['-c 3-']
281 ['--']
282 ['--']
283 ['-SHELL', 'a 1-']
284 ['-a 1', 'b 2-']
285 ['-c 3-']
286 ['--']
287 ['--']
288 ## END
289 ## N-I mksh status: 1
290 ## N-I mksh stdout-json: ""
291 ## BUG zsh stdout-json: ""
292
293 #### ${@:0:1}
294 set a b c
295 result=$(echo ${@:0:1})
296 echo ${result//"$0"/'SHELL'}
297 ## STDOUT:
298 SHELL
299 ## END
300 ## N-I mksh stdout-json: "\n"
301
302 #### Permutations of implicit begin and length
303 array=(1 2 3)
304
305 argv.py ${array[@]}
306
307 # *** implicit length of N **
308 argv.py ${array[@]:0}
309
310 # Why is this one not allowed
311 #argv.py ${array[@]:}
312
313 # ** implicit length of ZERO **
314 #argv.py ${array[@]::}
315 #argv.py ${array[@]:0:}
316
317 argv.py ${array[@]:0:0}
318 echo
319
320 # Same agreed upon permutations
321 set -- 1 2 3
322 argv.py ${@}
323 argv.py ${@:1}
324 argv.py ${@:1:0}
325 echo
326
327 s='123'
328 argv.py "${s}"
329 argv.py "${s:0}"
330 argv.py "${s:0:0}"
331
332 ## STDOUT:
333 ['1', '2', '3']
334 ['1', '2', '3']
335 []
336
337 ['1', '2', '3']
338 ['1', '2', '3']
339 []
340
341 ['123']
342 ['123']
343 ['']
344 ## END
345
346 ## BUG mksh status: 1
347 ## BUG mksh STDOUT:
348 ['1', '2', '3']
349 ## END
350
351 #### ${array[@]:} vs ${array[@]: } - bash and zsh inconsistent
352
353 $SH -c 'array=(1 2 3); argv.py ${array[@]:}'
354 $SH -c 'array=(1 2 3); argv.py space ${array[@]: }'
355
356 $SH -c 's=123; argv.py ${s:}'
357 $SH -c 's=123; argv.py space ${s: }'
358
359 ## STDOUT:
360 ['space', '1', '2', '3']
361 ['space', '123']
362 ## END
363
364 ## OK osh STDOUT:
365 ['1', '2', '3']
366 ['space', '1', '2', '3']
367 ['123']
368 ['space', '123']
369 ## END
370
371 ## BUG mksh STDOUT:
372 ['space', '123']
373 ## END
374
375 #### ${array[@]::} has implicit length of zero - for ble.sh
376
377 # https://oilshell.zulipchat.com/#narrow/stream/121540-oil-discuss/topic/.24.7Barr.5B.40.5D.3A.3A.7D.20in.20bash.20-.20is.20it.20documented.3F
378
379 array=(1 2 3)
380 argv.py ${array[@]::}
381 argv.py ${array[@]:0:}
382
383 echo
384
385 set -- 1 2 3
386 argv.py ${@::}
387 argv.py ${@:0:}
388
389 ## status: 0
390 ## STDOUT:
391
392 ## status: 0
393 ## STDOUT:
394 []
395 []
396
397 []
398 []
399 ## END
400
401 ## OK mksh/zsh status: 1
402 ## OK mksh/zsh STDOUT:
403 ## END