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 length |
8 |
v=foo |
9 |
echo ${#v} |
10 |
## stdout: 3 |
11 |
|
12 |
#### Unicode string length (UTF-8) |
13 |
v=$'_\u03bc_' |
14 |
echo ${#v} |
15 |
## stdout: 3 |
16 |
## N-I dash stdout: 9 |
17 |
## N-I mksh stdout: 4 |
18 |
|
19 |
#### Unicode string length (spec/testdata/utf8-chars.txt) |
20 |
v=$(cat spec/testdata/utf8-chars.txt) |
21 |
echo ${#v} |
22 |
## stdout: 7 |
23 |
## N-I dash stdout: 13 |
24 |
## N-I mksh stdout: 13 |
25 |
|
26 |
#### String length with incomplete utf-8 |
27 |
for num_bytes in 0 1 2 3 4 5 6 7 8 9 10 11 12 13; do |
28 |
s=$(head -c $num_bytes spec/testdata/utf8-chars.txt) |
29 |
echo ${#s} |
30 |
done |
31 |
## STDOUT: |
32 |
0 |
33 |
1 |
34 |
2 |
35 |
-1 |
36 |
3 |
37 |
4 |
38 |
-1 |
39 |
-1 |
40 |
5 |
41 |
6 |
42 |
-1 |
43 |
-1 |
44 |
-1 |
45 |
7 |
46 |
## END |
47 |
## STDERR: |
48 |
osh warning: Incomplete UTF-8 character |
49 |
osh warning: Incomplete UTF-8 character |
50 |
osh warning: Incomplete UTF-8 character |
51 |
osh warning: Incomplete UTF-8 character |
52 |
osh warning: Incomplete UTF-8 character |
53 |
osh warning: Incomplete UTF-8 character |
54 |
## END |
55 |
# zsh behavior actually matches bash! |
56 |
## BUG bash/zsh stderr-json: "" |
57 |
## BUG bash/zsh STDOUT: |
58 |
0 |
59 |
1 |
60 |
2 |
61 |
3 |
62 |
3 |
63 |
4 |
64 |
5 |
65 |
6 |
66 |
5 |
67 |
6 |
68 |
7 |
69 |
8 |
70 |
9 |
71 |
7 |
72 |
## END |
73 |
## BUG dash/mksh stderr-json: "" |
74 |
## N-I dash/mksh STDOUT: |
75 |
0 |
76 |
1 |
77 |
2 |
78 |
3 |
79 |
4 |
80 |
5 |
81 |
6 |
82 |
7 |
83 |
8 |
84 |
9 |
85 |
10 |
86 |
11 |
87 |
12 |
88 |
13 |
89 |
## END |
90 |
|
91 |
#### String length with invalid utf-8 continuation bytes |
92 |
for num_bytes in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14; do |
93 |
s=$(head -c $num_bytes spec/testdata/utf8-chars.txt)$(echo -e "\xFF") |
94 |
echo ${#s} |
95 |
done |
96 |
## STDOUT: |
97 |
-1 |
98 |
-1 |
99 |
-1 |
100 |
-1 |
101 |
-1 |
102 |
-1 |
103 |
-1 |
104 |
-1 |
105 |
-1 |
106 |
-1 |
107 |
-1 |
108 |
-1 |
109 |
-1 |
110 |
-1 |
111 |
-1 |
112 |
## END |
113 |
## STDERR: |
114 |
osh warning: Invalid start of UTF-8 character |
115 |
osh warning: Invalid start of UTF-8 character |
116 |
osh warning: Invalid start of UTF-8 character |
117 |
osh warning: Invalid UTF-8 continuation byte |
118 |
osh warning: Invalid start of UTF-8 character |
119 |
osh warning: Invalid start of UTF-8 character |
120 |
osh warning: Invalid UTF-8 continuation byte |
121 |
osh warning: Invalid UTF-8 continuation byte |
122 |
osh warning: Invalid start of UTF-8 character |
123 |
osh warning: Invalid start of UTF-8 character |
124 |
osh warning: Invalid UTF-8 continuation byte |
125 |
osh warning: Invalid UTF-8 continuation byte |
126 |
osh warning: Invalid UTF-8 continuation byte |
127 |
osh warning: Invalid start of UTF-8 character |
128 |
osh warning: Invalid start of UTF-8 character |
129 |
## END |
130 |
## BUG bash/zsh stderr-json: "" |
131 |
## BUG bash/zsh STDOUT: |
132 |
1 |
133 |
2 |
134 |
3 |
135 |
4 |
136 |
4 |
137 |
5 |
138 |
6 |
139 |
7 |
140 |
6 |
141 |
7 |
142 |
8 |
143 |
9 |
144 |
10 |
145 |
8 |
146 |
8 |
147 |
## N-I dash stderr-json: "" |
148 |
## N-I dash STDOUT: |
149 |
7 |
150 |
8 |
151 |
9 |
152 |
10 |
153 |
11 |
154 |
12 |
155 |
13 |
156 |
14 |
157 |
15 |
158 |
16 |
159 |
17 |
160 |
18 |
161 |
19 |
162 |
20 |
163 |
20 |
164 |
## END |
165 |
## N-I mksh stderr-json: "" |
166 |
## N-I mksh STDOUT: |
167 |
1 |
168 |
2 |
169 |
3 |
170 |
4 |
171 |
5 |
172 |
6 |
173 |
7 |
174 |
8 |
175 |
9 |
176 |
10 |
177 |
11 |
178 |
12 |
179 |
13 |
180 |
14 |
181 |
14 |
182 |
## END |
183 |
|
184 |
#### Length of undefined variable |
185 |
echo ${#undef} |
186 |
## stdout: 0 |
187 |
|
188 |
#### Length of undefined variable with nounset |
189 |
set -o nounset |
190 |
echo ${#undef} |
191 |
## status: 1 |
192 |
## OK dash status: 2 |
193 |
|
194 |
#### Cannot take length of substring slice |
195 |
# These are runtime errors, but we could make them parse time errors. |
196 |
v=abcde |
197 |
echo ${#v:1:3} |
198 |
## status: 1 |
199 |
## OK osh status: 2 |
200 |
## N-I dash status: 0 |
201 |
## N-I dash stdout: 5 |
202 |
# zsh actually implements this! |
203 |
## OK zsh stdout: 3 |
204 |
## OK zsh status: 0 |
205 |
|
206 |
#### Pattern replacement |
207 |
v=abcde |
208 |
echo ${v/c*/XX} |
209 |
## stdout: abXX |
210 |
## N-I dash status: 2 |
211 |
## N-I dash stdout-json: "" |
212 |
|
213 |
#### Pattern replacement on unset variable |
214 |
echo -${v/x/y}- |
215 |
echo status=$? |
216 |
set -o nounset # make sure this fails |
217 |
echo -${v/x/y}- |
218 |
## STDOUT: |
219 |
-- |
220 |
status=0 |
221 |
## BUG mksh STDOUT: |
222 |
# patsub disrespects nounset! |
223 |
-- |
224 |
status=0 |
225 |
-- |
226 |
## status: 1 |
227 |
## BUG mksh status: 0 |
228 |
## N-I dash status: 2 |
229 |
## N-I dash stdout-json: "" |
230 |
|
231 |
#### Global Pattern replacement with / |
232 |
s=xx_xx_xx |
233 |
echo ${s/xx?/yy_} ${s//xx?/yy_} |
234 |
## stdout: yy_xx_xx yy_yy_xx |
235 |
## N-I dash status: 2 |
236 |
## N-I dash stdout-json: "" |
237 |
|
238 |
#### Left Anchored Pattern replacement with # |
239 |
s=xx_xx_xx |
240 |
echo ${s/?xx/_yy} ${s/#?xx/_yy} |
241 |
## stdout: xx_yy_xx xx_xx_xx |
242 |
## N-I dash status: 2 |
243 |
## N-I dash stdout-json: "" |
244 |
|
245 |
#### Right Anchored Pattern replacement with % |
246 |
s=xx_xx_xx |
247 |
echo ${s/?xx/_yy} ${s/%?xx/_yy} |
248 |
## stdout: xx_yy_xx xx_xx_yy |
249 |
## N-I dash status: 2 |
250 |
## N-I dash stdout-json: "" |
251 |
|
252 |
#### Replace fixed strings |
253 |
s=xx_xx |
254 |
echo ${s/xx/yy} ${s//xx/yy} ${s/#xx/yy} ${s/%xx/yy} |
255 |
## stdout: yy_xx yy_yy yy_xx xx_yy |
256 |
## N-I dash status: 2 |
257 |
## N-I dash stdout-json: "" |
258 |
|
259 |
#### Replace is longest match |
260 |
# If it were shortest, then you would just replace the first <html> |
261 |
s='begin <html></html> end' |
262 |
echo ${s/<*>/[]} |
263 |
## stdout: begin [] end |
264 |
## N-I dash status: 2 |
265 |
## N-I dash stdout-json: "" |
266 |
|
267 |
#### Replace char class |
268 |
s=xx_xx_xx |
269 |
echo ${s//[[:alpha:]]/y} ${s//[^[:alpha:]]/-} |
270 |
## stdout: yy_yy_yy xx-xx-xx |
271 |
## N-I mksh stdout: xx_xx_xx xx_xx_xx |
272 |
## N-I dash status: 2 |
273 |
## N-I dash stdout-json: "" |
274 |
|
275 |
#### Replace hard glob |
276 |
s='aa*bb+cc' |
277 |
echo ${s//\**+/__} # Literal *, then any sequence of characters, then literal + |
278 |
## stdout: aa__cc |
279 |
## N-I dash status: 2 |
280 |
## N-I dash stdout-json: "" |
281 |
|
282 |
#### Pattern replacement ${v/} is not valid |
283 |
v=abcde |
284 |
echo -${v/}- |
285 |
echo status=$? |
286 |
## status: 2 |
287 |
## stdout-json: "" |
288 |
## N-I dash status: 2 |
289 |
## N-I dash stdout-json: "" |
290 |
## BUG bash/mksh/zsh status: 0 |
291 |
## BUG bash/mksh/zsh stdout-json: "-abcde-\nstatus=0\n" |
292 |
|
293 |
#### Pattern replacement ${v//} is not valid |
294 |
v='a/b/c' |
295 |
echo -${v//}- |
296 |
echo status=$? |
297 |
## status: 2 |
298 |
## stdout-json: "" |
299 |
## N-I dash status: 2 |
300 |
## N-I dash stdout-json: "" |
301 |
## BUG bash/mksh/zsh status: 0 |
302 |
## BUG bash/mksh/zsh stdout-json: "-a/b/c-\nstatus=0\n" |
303 |
|
304 |
#### ${v/a} is the same as ${v/a/} -- no replacement string |
305 |
v='aabb' |
306 |
echo ${v/a} |
307 |
echo status=$? |
308 |
## stdout-json: "abb\nstatus=0\n" |
309 |
## N-I dash stdout-json: "" |
310 |
## N-I dash status: 2 |
311 |
|
312 |
#### String slice |
313 |
foo=abcdefg |
314 |
echo ${foo:1:3} |
315 |
## STDOUT: |
316 |
bcd |
317 |
## END |
318 |
## N-I dash status: 2 |
319 |
## N-I dash stdout-json: "" |
320 |
|
321 |
#### Out of range string slice: begin |
322 |
# out of range begin doesn't raise error in bash, but in mksh it skips the |
323 |
# whole thing! |
324 |
foo=abcdefg |
325 |
echo _${foo:100:3} |
326 |
echo $? |
327 |
## STDOUT: |
328 |
_ |
329 |
0 |
330 |
## END |
331 |
## BUG mksh stdout-json: "\n0\n" |
332 |
## N-I dash status: 2 |
333 |
## N-I dash stdout-json: "" |
334 |
|
335 |
#### Out of range string slice: length |
336 |
# OK in both bash and mksh |
337 |
foo=abcdefg |
338 |
echo _${foo:3:100} |
339 |
echo $? |
340 |
## STDOUT: |
341 |
_defg |
342 |
0 |
343 |
## END |
344 |
## BUG mksh stdout-json: "_defg\n0\n" |
345 |
## N-I dash status: 2 |
346 |
## N-I dash stdout-json: "" |
347 |
|
348 |
#### String slice: negative begin |
349 |
foo=abcdefg |
350 |
echo ${foo: -4:3} |
351 |
## OK osh stdout: |
352 |
## stdout: def |
353 |
## N-I dash status: 2 |
354 |
## N-I dash stdout-json: "" |
355 |
|
356 |
#### String slice: negative second arg is position, not length |
357 |
foo=abcdefg |
358 |
echo ${foo:3:-1} ${foo: 3: -2} ${foo:3 :-3 } |
359 |
## OK osh stdout: |
360 |
## stdout: def de d |
361 |
## BUG mksh stdout: defg defg defg |
362 |
## N-I dash status: 2 |
363 |
## N-I dash stdout-json: "" |
364 |
|
365 |
#### strict-word-eval with string slice |
366 |
set -o strict-word-eval || true |
367 |
echo slice |
368 |
s='abc' |
369 |
echo -${s: -2}- |
370 |
## stdout-json: "slice\n" |
371 |
## status: 1 |
372 |
## N-I bash status: 0 |
373 |
## N-I bash stdout-json: "slice\n-bc-\n" |
374 |
## N-I dash status: 2 |
375 |
## N-I dash stdout-json: "" |
376 |
## N-I mksh/zsh status: 1 |
377 |
## N-I mksh/zsh stdout-json: "" |
378 |
|
379 |
#### String slice with math |
380 |
# I think this is the $(()) language inside? |
381 |
i=1 |
382 |
foo=abcdefg |
383 |
echo ${foo: i+4-2 : i + 2} |
384 |
## stdout: def |
385 |
## N-I dash status: 2 |
386 |
## N-I dash stdout-json: "" |
387 |
|
388 |
#### Slice undefined |
389 |
echo -${undef:1:2}- |
390 |
set -o nounset |
391 |
echo -${undef:1:2}- |
392 |
echo -done- |
393 |
## STDOUT: |
394 |
-- |
395 |
## END |
396 |
## status: 1 |
397 |
# mksh doesn't respect nounset! |
398 |
## BUG mksh status: 0 |
399 |
## BUG mksh STDOUT: |
400 |
-- |
401 |
-- |
402 |
-done- |
403 |
## END |
404 |
## N-I dash status: 2 |
405 |
## N-I dash stdout-json: "" |
406 |
|
407 |
#### Slice UTF-8 String |
408 |
# mksh slices by bytes. |
409 |
foo='--μ--' |
410 |
echo ${foo:1:3} |
411 |
## stdout: -μ- |
412 |
## BUG mksh stdout: -μ |
413 |
## N-I dash status: 2 |
414 |
## N-I dash stdout-json: "" |
415 |
|
416 |
#### Slice string with invalid UTF-8 results in empty string and warning |
417 |
s=$(echo -e "\xFF")bcdef |
418 |
echo -${s:1:3}- |
419 |
## status: 0 |
420 |
## stdout-json: "--\n" |
421 |
## stderr-json: "osh warning: Invalid start of UTF-8 character\n" |
422 |
## BUG bash/mksh/zsh status: 0 |
423 |
## BUG bash/mksh/zsh stdout-json: "-bcd-\n" |
424 |
## BUG bash/mksh/zsh stderr-json: "" |
425 |
## N-I dash status: 2 |
426 |
## N-I dash stdout-json: "" |
427 |
## N-I dash stderr-json: "_tmp/spec-bin/dash: 2: Bad substitution\n" |
428 |
|
429 |
|
430 |
#### Slice string with invalid UTF-8 with strict-word-eval |
431 |
set -o strict-word-eval || true |
432 |
echo slice |
433 |
s=$(echo -e "\xFF")bcdef |
434 |
echo -${s:1:3}- |
435 |
## status: 1 |
436 |
## stdout-json: "slice\n" |
437 |
## N-I mksh/zsh status: 1 |
438 |
## N-I mksh/zsh stdout-json: "" |
439 |
## N-I dash status: 2 |
440 |
## N-I dash stdout-json: "" |
441 |
## N-I bash status: 0 |
442 |
## N-I bash stdout-json: "slice\n-bcd-\n" |
443 |
|
444 |
#### Lower Case with , and ,, |
445 |
x='ABC DEF' |
446 |
echo ${x,} |
447 |
echo ${x,,} |
448 |
## STDOUT: |
449 |
aBC DEF |
450 |
abc def |
451 |
## END |
452 |
## N-I dash/mksh/zsh stdout-json: "" |
453 |
## N-I dash status: 2 |
454 |
## N-I mksh/zsh status: 1 |
455 |
|
456 |
|
457 |
#### Upper Case with ^ and ^^ |
458 |
x='abc def' |
459 |
echo ${x^} |
460 |
echo ${x^^} |
461 |
## STDOUT: |
462 |
Abc def |
463 |
ABC DEF |
464 |
## END |
465 |
## N-I dash/mksh/zsh stdout-json: "" |
466 |
## N-I dash status: 2 |
467 |
## N-I mksh/zsh status: 1 |
468 |
|
469 |
#### Lower Case with constant string (VERY WEIRD) |
470 |
x='AAA ABC DEF' |
471 |
echo ${x,A} |
472 |
echo ${x,,A} # replaces every A only? |
473 |
## STDOUT: |
474 |
aAA ABC DEF |
475 |
aaa aBC DEF |
476 |
## END |
477 |
## N-I dash/mksh/zsh stdout-json: "" |
478 |
## N-I dash status: 2 |
479 |
## N-I mksh/zsh status: 1 |
480 |
|
481 |
#### Lower Case glob |
482 |
x='ABC DEF' |
483 |
echo ${x,[d-f]} |
484 |
echo ${x,,[d-f]} # This seems buggy, it doesn't include F? |
485 |
## STDOUT: |
486 |
ABC DEF |
487 |
ABC deF |
488 |
## END |
489 |
## N-I dash/mksh/zsh stdout-json: "" |
490 |
## N-I dash status: 2 |
491 |
## N-I mksh/zsh status: 1 |