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