OILS / spec / var-op-slice.test.sh View on Github | oils.pub

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