OILS / spec / var-op-slice.test.sh View on Github | oilshell.org

403 lines, 218 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-json: "\n0\n"
35
36#### Out of range string slice: length
37# OK in both bash and mksh
38foo=abcdefg
39echo _${foo:3:100}
40echo $?
41## STDOUT:
42_defg
430
44## END
45## BUG mksh stdout-json: "_defg\n0\n"
46
47#### Negative start index
48foo=abcdefg
49echo ${foo: -4:3}
50## stdout: def
51
52#### Negative start index respects unicode
53foo=abcd-μ-
54echo ${foo: -4:3}
55## stdout: d-μ
56## BUG mksh stdout: -μ
57
58#### Negative second arg is position, not length!
59foo=abcdefg
60echo ${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
65foo=abcd-μ-
66echo ${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?
72i=1
73foo=abcdefg
74echo ${foo: i+4-2 : i + 2}
75## stdout: def
76
77#### Slice undefined
78echo -${undef:1:2}-
79set -o nounset
80echo -${undef:1:2}-
81echo -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.
96foo='--μ--'
97echo ${foo:1:3}
98## stdout: -μ-
99## BUG mksh stdout: -μ
100
101#### Slice string with invalid UTF-8 results in empty string and warning
102s=$(echo -e "\xFF")bcdef
103echo -${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
119shopt -s strict_word_eval || true
120echo slice
121s=$(echo -e "\xFF")bcdef
122echo -${s:1:3}-
123## status: 1
124## STDOUT:
125slice
126## END
127## N-I bash/mksh/zsh status: 0
128## N-I bash/mksh/zsh STDOUT:
129slice
130-bcd-
131## END
132
133#### Slice with an index that's an array -- silent a[0] decay
134i=(3 4 5)
135mystr=abcdefg
136echo assigned
137echo ${mystr:$i:2}
138
139## status: 0
140## STDOUT:
141assigned
142de
143## END
144## OK zsh status: 1
145## OK zsh STDOUT:
146assigned
147## END
148
149#### Slice with an assoc array
150declare -A A=(['5']=3 ['6']=4)
151mystr=abcdefg
152echo assigned
153echo ${mystr:$A:2}
154
155## status: 0
156## STDOUT:
157assigned
158ab
159## END
160
161## N-I mksh status: 1
162## N-I mksh stdout-json: ""
163
164#### Simple ${@:offset}
165
166set -- 4 5 6
167
168result=$(argv.py ${@:0})
169echo ${result//"$0"/'SHELL'}
170
171argv.py ${@:1}
172argv.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}
184case $SH in (zsh) return ;; esac # zsh is very different
185
186argv.shell-name-checked () {
187 argv.py "${@//$0/SHELL}"
188}
189fun() {
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}
211fun "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}
239case $SH in (zsh) return ;; esac # zsh is very different
240
241argv.shell-name-checked () {
242 argv.py "${@//$0/SHELL}"
243}
244fun() {
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}
266fun "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}
294set a b c
295result=$(echo ${@:0:1})
296echo ${result//"$0"/'SHELL'}
297## STDOUT:
298SHELL
299## END
300## N-I mksh stdout-json: "\n"
301
302#### Permutations of implicit begin and length
303array=(1 2 3)
304
305argv.py ${array[@]}
306
307# *** implicit length of N **
308argv.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
317argv.py ${array[@]:0:0}
318echo
319
320# Same agreed upon permutations
321set -- 1 2 3
322argv.py ${@}
323argv.py ${@:1}
324argv.py ${@:1:0}
325echo
326
327s='123'
328argv.py "${s}"
329argv.py "${s:0}"
330argv.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
379array=(1 2 3)
380argv.py ${array[@]::}
381argv.py ${array[@]:0:}
382
383echo
384
385set -- 1 2 3
386argv.py ${@::}
387argv.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