1 #!/usr/bin/env bash
2 #
3 # Test combination of var ops.
4 #
5 # NOTE: There are also slice tests in {array,arith-context}.test.sh.
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: Invalid start of UTF-8 character
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 itself not allowed
134 i=(3 4 5)
135 mystr=abcdefg
136 echo assigned
137 echo ${mystr:$i:2}
138 ## status: 1
139 ## STDOUT:
140 assigned
141 ## END
142 ## BUG mksh/bash status: 0
143 ## BUG mksh/bash STDOUT:
144 assigned
145 de
146 ## END
147
148 #### Slice with an assoc array
149 declare -A A=(['5']=3 ['6']=4)
150 mystr=abcdefg
151 echo assigned
152 echo ${mystr:$A:2}
153 ## status: 1
154 ## STDOUT:
155 assigned
156 ## END
157 ## N-I mksh stdout-json: ""
158 ## BUG bash/zsh status: 0
159 ## BUG bash/zsh STDOUT:
160 assigned
161 ab
162 ## END
163
164 #### Simple ${@:offset}
165
166 set -- 4 5 6
167 result=$(argv.py ${@:0})
168 echo ${result//"$0"/'SHELL'}
169 argv.py ${@:1}
170 argv.py ${@:2}
171 ## STDOUT:
172 ['SHELL', '4', '5', '6']
173 ['4', '5', '6']
174 ['5', '6']
175 ## END
176 ## N-I mksh status: 1
177 ## N-I mksh stdout-json: "\n"
178
179
180 #### ${@:offset} and ${*:offset}
181 case $SH in (zsh) return ;; esac # zsh is very different
182
183 argv.shell-name-checked () {
184 argv.py "${@//$0/SHELL}"
185 }
186 fun() {
187 argv.shell-name-checked -${*:0}- # include $0
188 argv.shell-name-checked -${*:1}- # from $1
189 argv.shell-name-checked -${*:3}- # last parameter $3
190 argv.shell-name-checked -${*:4}- # empty
191 argv.shell-name-checked -${*:5}- # out of boundary
192 argv.shell-name-checked -${@:0}-
193 argv.shell-name-checked -${@:1}-
194 argv.shell-name-checked -${@:3}-
195 argv.shell-name-checked -${@:4}-
196 argv.shell-name-checked -${@:5}-
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 }
208 fun "a 1" "b 2" "c 3"
209 ## STDOUT:
210 ['-SHELL', 'a', '1', 'b', '2', 'c', '3-']
211 ['-a', '1', 'b', '2', 'c', '3-']
212 ['-c', '3-']
213 ['--']
214 ['--']
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 ## END
231 ## N-I mksh status: 1
232 ## N-I mksh stdout-json: ""
233 ## BUG zsh stdout-json: ""
234
235 #### ${@:offset:length} and ${*:offset:length}
236 case $SH in (zsh) return ;; esac # zsh is very different
237
238 argv.shell-name-checked () {
239 argv.py "${@//$0/SHELL}"
240 }
241 fun() {
242 argv.shell-name-checked -${*:0:2}- # include $0
243 argv.shell-name-checked -${*:1:2}- # from $1
244 argv.shell-name-checked -${*:3:2}- # last parameter $3
245 argv.shell-name-checked -${*:4:2}- # empty
246 argv.shell-name-checked -${*:5:2}- # out of boundary
247 argv.shell-name-checked -${@:0:2}-
248 argv.shell-name-checked -${@:1:2}-
249 argv.shell-name-checked -${@:3:2}-
250 argv.shell-name-checked -${@:4:2}-
251 argv.shell-name-checked -${@:5:2}-
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 }
263 fun "a 1" "b 2" "c 3"
264 ## STDOUT:
265 ['-SHELL', 'a', '1-']
266 ['-a', '1', 'b', '2-']
267 ['-c', '3-']
268 ['--']
269 ['--']
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 ## END
286 ## N-I mksh status: 1
287 ## N-I mksh stdout-json: ""
288 ## BUG zsh stdout-json: ""
289
290 #### ${@:0:1}
291 set a b c
292 result=$(echo ${@:0:1})
293 echo ${result//"$0"/'SHELL'}
294 ## STDOUT:
295 SHELL
296 ## END
297 ## N-I mksh stdout-json: "\n"
298
299 #### ${array[@]::0}
300 array=(1 2 3)
301 argv.py ${array[@]::0}
302 ## STDOUT:
303 []
304 ## END
305 ## N-I mksh/zsh status: 1
306 ## N-I mksh/zsh stdout-json: ""
307
308 #### ${array[@]::}
309 array=(1 2 3)
310 argv.py ${array[@]::}
311 ## STDOUT:
312 []
313 ## END
314 ## N-I mksh/zsh status: 1
315 ## N-I mksh/zsh status: 1
316 ## N-I mksh/zsh stdout-json: ""