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