OILS / spec / var-op-test.test.sh View on Github | oils.pub

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