1 ## oils_failures_allowed: 1
2 ## compare_shells: bash dash mksh zsh
3
4 #### Lazy Evaluation of Alternative
5 i=0
6 x=x
7 echo ${x:-$((i++))}
8 echo $i
9 echo ${undefined:-$((i++))}
10 echo $i # i is one because the alternative was only evaluated once
11 ## status: 0
12 ## stdout-json: "x\n0\n0\n1\n"
13 ## N-I dash status: 2
14 ## N-I dash stdout-json: "x\n0\n"
15
16 #### Default value when empty
17 empty=''
18 echo ${empty:-is empty}
19 ## stdout: is empty
20
21 #### Default value when unset
22 echo ${unset-is unset}
23 ## stdout: is unset
24
25 #### Unquoted with array as default value
26 set -- '1 2' '3 4'
27 argv.py X${unset=x"$@"x}X
28 argv.py X${unset=x$@x}X # If you want OSH to split, write this
29 # osh
30 ## STDOUT:
31 ['Xx1', '2', '3', '4xX']
32 ['Xx1', '2', '3', '4xX']
33 ## END
34 ## OK osh STDOUT:
35 ['Xx1 2', '3 4xX']
36 ['Xx1', '2', '3', '4xX']
37 ## END
38 ## OK zsh STDOUT:
39 ['Xx1 2 3 4xX']
40 ['Xx1 2 3 4xX']
41 ## END
42
43 #### Quoted with array as default value
44 set -- '1 2' '3 4'
45 argv.py "X${unset=x"$@"x}X"
46 argv.py "X${unset=x$@x}X" # OSH is the same here
47 ## STDOUT:
48 ['Xx1 2 3 4xX']
49 ['Xx1 2 3 4xX']
50 ## END
51 ## BUG bash STDOUT:
52 ['Xx1', '2', '3', '4xX']
53 ['Xx1 2 3 4xX']
54 ## END
55 ## OK osh STDOUT:
56 ['Xx1 2', '3 4xX']
57 ['Xx1 2 3 4xX']
58 ## END
59
60 #### Assign default with array
61 set -- '1 2' '3 4'
62 argv.py X${unset=x"$@"x}X
63 argv.py "$unset"
64 ## STDOUT:
65 ['Xx1', '2', '3', '4xX']
66 ['x1 2 3 4x']
67 ## END
68 ## OK osh STDOUT:
69 ['Xx1 2', '3 4xX']
70 ['x1 2 3 4x']
71 ## END
72 ## OK zsh STDOUT:
73 ['Xx1 2 3 4xX']
74 ['x1 2 3 4x']
75 ## END
76
77 #### Assign default value when empty
78 empty=''
79 ${empty:=is empty}
80 echo $empty
81 ## stdout: is empty
82
83 #### Assign default value when unset
84 ${unset=is unset}
85 echo $unset
86 ## stdout: is unset
87
88 #### ${v:+foo} Alternative value when empty
89 v=foo
90 empty=''
91 echo ${v:+v is not empty} ${empty:+is not empty}
92 ## stdout: v is not empty
93
94 #### ${v+foo} Alternative value when unset
95 v=foo
96 echo ${v+v is not unset} ${unset:+is not unset}
97 ## stdout: v is not unset
98
99 #### "${x+foo}" quoted (regression)
100 # Python's configure caught this
101 argv.py "${with_icc+set}" = set
102 ## STDOUT:
103 ['', '=', 'set']
104 ## END
105
106 #### ${s+foo} and ${s:+foo} when set -u
107 set -u
108 v=v
109 echo v=${v:+foo}
110 echo v=${v+foo}
111 unset v
112 echo v=${v:+foo}
113 echo v=${v+foo}
114 ## STDOUT:
115 v=foo
116 v=foo
117 v=
118 v=
119 ## END
120
121 #### "${array[@]} with set -u (bash is outlier)
122 case $SH in dash) exit ;; esac
123
124 set -u
125
126 typeset -a empty
127 empty=()
128
129 echo empty /"${empty[@]}"/
130 echo undefined /"${undefined[@]}"/
131
132 ## status: 1
133 ## STDOUT:
134 empty //
135 ## END
136
137 ## BUG bash status: 0
138 ## BUG bash STDOUT:
139 empty //
140 undefined //
141 ## END
142
143 # empty array is unset in mksh
144 ## BUG mksh status: 1
145 ## BUG mksh STDOUT:
146 ## END
147
148 ## N-I dash status: 0
149 ## N-I dash STDOUT:
150 ## END
151
152
153 #### "${undefined[@]+foo}" and "${undefined[@]:+foo}", with set -u
154 case $SH in dash) exit ;; esac
155
156 set -u
157
158 echo plus /"${array[@]+foo}"/
159 echo plus colon /"${array[@]:+foo}"/
160
161 ## STDOUT:
162 plus //
163 plus colon //
164 ## END
165
166 ## N-I dash STDOUT:
167 ## END
168
169 #### "${a[@]+foo}" and "${a[@]:+foo}" - operators are equivalent on arrays?
170
171 case $SH in dash) exit ;; esac
172
173 echo '+ ' /"${array[@]+foo}"/
174 echo '+:' /"${array[@]:+foo}"/
175 echo
176
177 typeset -a array
178 array=()
179
180 echo '+ ' /"${array[@]+foo}"/
181 echo '+:' /"${array[@]:+foo}"/
182 echo
183
184 array=('')
185
186 echo '+ ' /"${array[@]+foo}"/
187 echo '+:' /"${array[@]:+foo}"/
188 echo
189
190 array=(spam eggs)
191
192 echo '+ ' /"${array[@]+foo}"/
193 echo '+:' /"${array[@]:+foo}"/
194 echo
195
196
197 ## STDOUT:
198 + //
199 +: //
200
201 + //
202 +: //
203
204 + /foo/
205 +: /foo/
206
207 + /foo/
208 +: /foo/
209
210 ## END
211
212 ## BUG mksh STDOUT:
213 + //
214 +: //
215
216 + //
217 +: //
218
219 + /foo/
220 +: //
221
222 + /foo/
223 +: /foo/
224
225 ## END
226
227 ## BUG zsh STDOUT:
228 + //
229 +: //
230
231 + /foo/
232 +: //
233
234 + /foo/
235 +: /foo/
236
237 + /foo/
238 +: /foo/
239
240 ## END
241
242 ## N-I dash STDOUT:
243 ## END
244
245
246
247 #### Nix idiom ${!hooksSlice+"${!hooksSlice}"} - was workaround for obsolete bash 4.3 bug
248
249 case $SH in dash|mksh|zsh) exit ;; esac
250
251 # https://oilshell.zulipchat.com/#narrow/stream/307442-nix/topic/Replacing.20bash.20with.20osh.20in.20Nixpkgs.20stdenv
252
253 argv.py ${!hooksSlice+"${!hooksSlice}"}
254
255 declare -a hookSlice=()
256
257 argv.py ${!hooksSlice+"${!hooksSlice}"}
258
259 foo=42
260 bar=43
261
262 declare -a hookSlice=(foo bar spam eggs)
263
264 argv.py ${!hooksSlice+"${!hooksSlice}"}
265
266 ## STDOUT:
267 []
268 []
269 []
270 ## END
271
272 ## OK dash/mksh/zsh STDOUT:
273 ## END
274
275 #### ${v-foo} and ${v:-foo} when set -u
276 set -u
277 v=v
278 echo v=${v:-foo}
279 echo v=${v-foo}
280 unset v
281 echo v=${v:-foo}
282 echo v=${v-foo}
283 ## STDOUT:
284 v=v
285 v=v
286 v=foo
287 v=foo
288 ## END
289
290 #### array and - and +
291 case $SH in (dash) exit ;; esac
292
293 shopt -s compat_array # to refer to array as scalar
294
295 empty=()
296 a1=('')
297 a2=('' x)
298 a3=(3 4)
299 echo empty=${empty[@]-minus}
300 echo a1=${a1[@]-minus}
301 echo a1[0]=${a1[0]-minus}
302 echo a2=${a2[@]-minus}
303 echo a3=${a3[@]-minus}
304 echo ---
305
306 echo empty=${empty[@]+plus}
307 echo a1=${a1[@]+plus}
308 echo a1[0]=${a1[0]+plus}
309 echo a2=${a2[@]+plus}
310 echo a3=${a3[@]+plus}
311 echo ---
312
313 echo empty=${empty+plus}
314 echo a1=${a1+plus}
315 echo a2=${a2+plus}
316 echo a3=${a3+plus}
317 echo ---
318
319 # Test quoted arrays too
320 argv.py "${empty[@]-minus}"
321 argv.py "${empty[@]+plus}"
322 argv.py "${a1[@]-minus}"
323 argv.py "${a1[@]+plus}"
324 argv.py "${a1[0]-minus}"
325 argv.py "${a1[0]+plus}"
326 argv.py "${a2[@]-minus}"
327 argv.py "${a2[@]+plus}"
328 argv.py "${a3[@]-minus}"
329 argv.py "${a3[@]+plus}"
330
331 ## STDOUT:
332 empty=minus
333 a1=
334 a1[0]=
335 a2= x
336 a3=3 4
337 ---
338 empty=
339 a1=plus
340 a1[0]=plus
341 a2=plus
342 a3=plus
343 ---
344 empty=
345 a1=plus
346 a2=plus
347 a3=plus
348 ---
349 ['minus']
350 []
351 ['']
352 ['plus']
353 ['']
354 ['plus']
355 ['', 'x']
356 ['plus']
357 ['3', '4']
358 ['plus']
359 ## END
360 ## N-I dash stdout-json: ""
361 ## N-I zsh stdout-json: "empty=\na1=\n"
362 ## N-I zsh status: 1
363
364 #### $@ and - and +
365 echo argv=${@-minus}
366 echo argv=${@+plus}
367 echo argv=${@:-minus}
368 echo argv=${@:+plus}
369 ## STDOUT:
370 argv=minus
371 argv=
372 argv=minus
373 argv=
374 ## END
375 ## BUG dash/zsh STDOUT:
376 argv=
377 argv=plus
378 argv=minus
379 argv=
380 ## END
381
382 #### assoc array and - and +
383 case $SH in (dash|mksh) exit ;; esac
384
385 declare -A empty=()
386 declare -A assoc=(['k']=v)
387
388 echo empty=${empty[@]-minus}
389 echo empty=${empty[@]+plus}
390 echo assoc=${assoc[@]-minus}
391 echo assoc=${assoc[@]+plus}
392
393 echo ---
394 echo empty=${empty[@]:-minus}
395 echo empty=${empty[@]:+plus}
396 echo assoc=${assoc[@]:-minus}
397 echo assoc=${assoc[@]:+plus}
398 ## STDOUT:
399 empty=minus
400 empty=
401 assoc=v
402 assoc=plus
403 ---
404 empty=minus
405 empty=
406 assoc=v
407 assoc=plus
408 ## END
409
410 ## BUG zsh STDOUT:
411 empty=
412 empty=plus
413 assoc=minus
414 assoc=
415 ---
416 empty=minus
417 empty=
418 assoc=minus
419 assoc=
420 ## END
421
422 ## N-I dash/mksh STDOUT:
423 ## END
424
425
426 #### Error when empty
427 empty=''
428 echo ${empty:?'is em'pty} # test eval of error
429 echo should not get here
430 ## stdout-json: ""
431 ## status: 1
432 ## OK dash status: 2
433
434 #### Error when unset
435 echo ${unset?is empty}
436 echo should not get here
437 ## stdout-json: ""
438 ## status: 1
439 ## OK dash status: 2
440
441 #### Error when unset
442 v=foo
443 echo ${v+v is not unset} ${unset:+is not unset}
444 ## stdout: v is not unset
445
446 #### ${var=x} dynamic scope
447 f() { : "${hello:=x}"; echo $hello; }
448 f
449 echo hello=$hello
450
451 f() { hello=x; }
452 f
453 echo hello=$hello
454 ## STDOUT:
455 x
456 hello=x
457 hello=x
458 ## END
459
460 #### array ${arr[0]=x}
461 arr=()
462 echo ${#arr[@]}
463 : ${arr[0]=x}
464 echo ${#arr[@]}
465 ## STDOUT:
466 0
467 1
468 ## END
469 ## N-I dash status: 2
470 ## N-I dash stdout-json: ""
471 ## N-I zsh status: 1
472 ## N-I zsh stdout-json: "0\n"
473
474 #### assoc array ${arr["k"]=x}
475 # note: this also works in zsh
476
477 declare -A arr=()
478 echo ${#arr[@]}
479 : ${arr['k']=x}
480 echo ${#arr[@]}
481 ## STDOUT:
482 0
483 1
484 ## END
485 ## N-I dash status: 2
486 ## N-I dash stdout-json: ""
487 ## N-I mksh status: 1
488 ## N-I mksh stdout-json: ""
489
490 #### "\z" as arg
491 echo "${undef-\$}"
492 echo "${undef-\(}"
493 echo "${undef-\z}"
494 echo "${undef-\"}"
495 echo "${undef-\`}"
496 echo "${undef-\\}"
497 ## STDOUT:
498 $
499 \(
500 \z
501 "
502 `
503 \
504 ## END
505 ## BUG yash STDOUT:
506 $
507 (
508 z
509 "
510 `
511 \
512 ## END
513
514 #### "\e" as arg
515 echo "${undef-\e}"
516 ## STDOUT:
517 \e
518 ## END
519 ## BUG zsh/mksh stdout-repr: '\x1b\n'
520 ## BUG yash stdout: e
521