OILS / spec / assign-extended.test.sh View on Github | oilshell.org

876 lines, 552 significant
1## compare_shells: bash-4.4 mksh
2
3
4# Extended assignment language, e.g. typeset, declare, arrays, etc.
5# Things that dash doesn't support.
6
7#### local -a
8# nixpkgs setup.sh uses this (issue #26)
9f() {
10 local -a array=(x y z)
11 argv.py "${array[@]}"
12}
13f
14## stdout: ['x', 'y', 'z']
15## N-I mksh stdout-json: ""
16## N-I mksh status: 1
17
18#### declare -a
19# nixpkgs setup.sh uses this (issue #26)
20declare -a array=(x y z)
21argv.py "${array[@]}"
22## stdout: ['x', 'y', 'z']
23## N-I mksh stdout-json: ""
24## N-I mksh status: 1
25
26#### indexed LHS with spaces (not allowed in OSH)
27a[1 * 1]=x a[ 1 + 2 ]=z
28echo status=$?
29argv.py "${a[@]}"
30## STDOUT:
31status=0
32['x', 'z']
33## END
34## N-I osh STDOUT:
35status=127
36[]
37## END
38
39#### declare -f exit code indicates function existence
40func2=x # var names are NOT found
41declare -f myfunc func2
42echo $?
43
44myfunc() { echo myfunc; }
45# This prints the source code.
46declare -f myfunc func2 > /dev/null
47echo $?
48
49func2() { echo func2; }
50declare -f myfunc func2 > /dev/null
51echo $?
52## STDOUT:
531
541
550
56## END
57## N-I mksh STDOUT:
58127
59127
60127
61## END
62
63#### declare -F prints function names
64add () { expr 4 + 4; }
65div () { expr 6 / 2; }
66ek () { echo hello; }
67__ec () { echo hi; }
68_ab () { expr 10 % 3; }
69
70declare -F
71## STDOUT:
72declare -f __ec
73declare -f _ab
74declare -f add
75declare -f div
76declare -f ek
77## END
78## N-I mksh stdout-json: ""
79## N-I mksh status: 127
80
81#### declare -p var (exit status)
82var1() { echo func; } # function names are NOT found.
83declare -p var1 var2 >/dev/null
84echo $?
85
86var1=x
87declare -p var1 var2 >/dev/null
88echo $?
89
90var2=y
91declare -p var1 var2 >/dev/null
92echo $?
93## STDOUT:
941
951
960
97## N-I mksh STDOUT:
98127
99127
100127
101## END
102
103#### declare
104test_var1=111
105readonly test_var2=222
106export test_var3=333
107declare -n test_var4=test_var1
108f1() {
109 local test_var5=555
110 {
111 echo '[declare]'
112 declare
113 echo '[readonly]'
114 readonly
115 echo '[export]'
116 export
117 echo '[local]'
118 local
119 } | grep -E '^\[|^\b.*test_var.\b'
120}
121f1
122## STDOUT:
123[declare]
124test_var1=111
125test_var2=222
126test_var3=333
127test_var4=test_var1
128test_var5=555
129[readonly]
130declare -r test_var2=222
131[export]
132declare -x test_var3=333
133[local]
134test_var5=555
135## END
136## OK bash STDOUT:
137[declare]
138test_var1=111
139test_var2=222
140test_var3=333
141test_var4=test_var1
142test_var5=555
143[readonly]
144declare -r test_var2="222"
145[export]
146declare -x test_var3="333"
147[local]
148test_var5=555
149## END
150## N-I mksh STDOUT:
151[declare]
152[readonly]
153test_var2
154[export]
155test_var3
156[local]
157typeset test_var1
158typeset -r test_var2
159typeset -x test_var3
160typeset test_var5
161## END
162
163#### declare -p
164# BUG: bash doesn't output flags with "local -p", which seems to contradict
165# with manual.
166test_var1=111
167readonly test_var2=222
168export test_var3=333
169declare -n test_var4=test_var1
170f1() {
171 local test_var5=555
172 {
173 echo '[declare]'
174 declare -p
175 echo '[readonly]'
176 readonly -p
177 echo '[export]'
178 export -p
179 echo '[local]'
180 local -p
181 } | grep -E '^\[|^\b.*test_var.\b'
182}
183f1
184## STDOUT:
185[declare]
186declare -- test_var1=111
187declare -r test_var2=222
188declare -x test_var3=333
189declare -n test_var4=test_var1
190declare -- test_var5=555
191[readonly]
192declare -r test_var2=222
193[export]
194declare -x test_var3=333
195[local]
196declare -- test_var5=555
197## END
198## BUG bash STDOUT:
199[declare]
200declare -- test_var1="111"
201declare -r test_var2="222"
202declare -x test_var3="333"
203declare -n test_var4="test_var1"
204declare -- test_var5="555"
205[readonly]
206declare -r test_var2="222"
207[export]
208declare -x test_var3="333"
209[local]
210test_var5=555
211## END
212## N-I mksh STDOUT:
213[declare]
214[readonly]
215readonly test_var2=222
216[export]
217export test_var3=333
218[local]
219typeset test_var1=111
220typeset -r test_var2=222
221typeset -x test_var3=333
222typeset test_var5=555
223## END
224
225#### declare -p doesn't print binary data, but can be loaded into bash
226
227# bash prints binary data!
228case $SH in bash*|mksh) exit ;; esac
229
230unquoted='foo'
231sq='foo bar'
232bash1=$'\x1f' # ASCII control char
233bash2=$'\xfe\xff' # Invalid UTF-8
234
235s1=$unquoted
236s2=$sq
237s3=$bash1
238s4=$bash2
239
240declare -a a=("$unquoted" "$sq" "$bash1" "$bash2")
241declare -A A=(["$unquoted"]="$sq" ["$bash1"]="$bash2")
242
243#echo lengths ${#s1} ${#s2} ${#s3} ${#s4} ${#a[@]} ${#A[@]}
244
245declare -p s1 s2 s3 s4 a A | tee tmp.bash
246
247echo ---
248
249bash -c 'source tmp.bash; echo "$s1 $s2"; echo -n "$s3" "$s4" | od -A n -t x1'
250echo bash=$?
251
252## STDOUT:
253declare -- s1=foo
254declare -- s2='foo bar'
255declare -- s3=$'\u001f'
256declare -- s4=$'\xfe\xff'
257declare -a a=(foo 'foo bar' $'\u001f' $'\xfe\xff')
258declare -A A=([$'\u001f']=$'\xfe\xff' ['foo']='foo bar')
259---
260foo foo bar
261 1f 20 fe ff
262bash=0
263## END
264
265## N-I bash/mksh STDOUT:
266## END
267
268
269
270#### declare -p var
271# BUG? bash doesn't output anything for 'local/readonly -p var', which seems to
272# contradict with manual. Besides, 'export -p var' is not described in
273# manual
274test_var1=111
275readonly test_var2=222
276export test_var3=333
277declare -n test_var4=test_var1
278f1() {
279 local test_var5=555
280 {
281 echo '[declare]'
282 declare -p test_var{0..5}
283 echo '[readonly]'
284 readonly -p test_var{0..5}
285 echo '[export]'
286 export -p test_var{0..5}
287 echo '[local]'
288 local -p test_var{0..5}
289 } | grep -E '^\[|^\b.*test_var.\b'
290}
291f1
292## STDOUT:
293[declare]
294declare -- test_var1=111
295declare -r test_var2=222
296declare -x test_var3=333
297declare -n test_var4=test_var1
298declare -- test_var5=555
299[readonly]
300declare -r test_var2=222
301[export]
302declare -x test_var3=333
303[local]
304declare -- test_var5=555
305## END
306## BUG bash STDOUT:
307[declare]
308declare -- test_var1="111"
309declare -r test_var2="222"
310declare -x test_var3="333"
311declare -n test_var4="test_var1"
312declare -- test_var5="555"
313[readonly]
314[export]
315[local]
316## END
317## N-I mksh STDOUT:
318[declare]
319[readonly]
320## END
321
322#### declare -p arr
323test_arr1=()
324declare -a test_arr2=()
325declare -A test_arr3=()
326test_arr4=(1 2 3)
327declare -a test_arr5=(1 2 3)
328declare -A test_arr6=(['a']=1 ['b']=2 ['c']=3)
329test_arr7=()
330test_arr7[3]=foo
331declare -p test_arr{1..7}
332## STDOUT:
333declare -a test_arr1=()
334declare -a test_arr2=()
335declare -A test_arr3
336declare -a test_arr4=(1 2 3)
337declare -a test_arr5=(1 2 3)
338declare -A test_arr6=(['a']=1 ['b']=2 ['c']=3)
339declare -a test_arr7=(); test_arr7[3]=foo
340## END
341## OK bash STDOUT:
342declare -a test_arr1=()
343declare -a test_arr2=()
344declare -A test_arr3=()
345declare -a test_arr4=([0]="1" [1]="2" [2]="3")
346declare -a test_arr5=([0]="1" [1]="2" [2]="3")
347declare -A test_arr6=([a]="1" [b]="2" [c]="3" )
348declare -a test_arr7=([3]="foo")
349## END
350## N-I mksh stdout-json: ""
351## N-I mksh status: 1
352
353#### declare -p foo=bar doesn't make sense
354case $SH in (mksh) exit 0; esac
355
356declare -p foo=bar
357echo status=$?
358
359a=b
360declare -p a foo=bar > tmp.txt
361echo status=$?
362sed 's/"//g' tmp.txt # don't care about quotes
363## STDOUT:
364status=1
365status=1
366declare -- a=b
367## END
368## N-I mksh stdout-json: ""
369
370#### declare -pnrx
371test_var1=111
372readonly test_var2=222
373export test_var3=333
374declare -n test_var4=test_var1
375f1() {
376 local test_var5=555
377 {
378 echo '[declare -pn]'
379 declare -pn
380 echo '[declare -pr]'
381 declare -pr
382 echo '[declare -px]'
383 declare -px
384 } | grep -E '^\[|^\b.*test_var.\b'
385}
386f1
387## STDOUT:
388[declare -pn]
389declare -n test_var4=test_var1
390[declare -pr]
391declare -r test_var2=222
392[declare -px]
393declare -x test_var3=333
394## END
395## OK bash STDOUT:
396[declare -pn]
397declare -n test_var4="test_var1"
398[declare -pr]
399declare -r test_var2="222"
400[declare -px]
401declare -x test_var3="333"
402## END
403## N-I mksh STDOUT:
404[declare -pn]
405[declare -pr]
406[declare -px]
407## END
408
409#### declare -paA
410declare -a test_var6=()
411declare -A test_var7=()
412f1() {
413 {
414 echo '[declare -pa]'
415 declare -pa
416 echo '[declare -pA]'
417 declare -pA
418 } | grep -E '^\[|^\b.*test_var.\b'
419}
420f1
421## STDOUT:
422[declare -pa]
423declare -a test_var6=()
424[declare -pA]
425declare -A test_var7
426## END
427## OK bash STDOUT:
428[declare -pa]
429declare -a test_var6=()
430[declare -pA]
431declare -A test_var7=()
432## END
433## N-I mksh stdout-json: ""
434## N-I mksh status: 1
435
436#### declare -pnrx var
437# Note: Bash ignores other flags (-nrx) when variable names are supplied while
438# OSH uses other flags to select variables. Bash's behavior is documented.
439test_var1=111
440readonly test_var2=222
441export test_var3=333
442declare -n test_var4=test_var1
443f1() {
444 local test_var5=555
445 {
446 echo '[declare -pn]'
447 declare -pn test_var{0..5}
448 echo '[declare -pr]'
449 declare -pr test_var{0..5}
450 echo '[declare -px]'
451 declare -px test_var{0..5}
452 } | grep -E '^\[|^\b.*test_var.\b'
453}
454f1
455## STDOUT:
456[declare -pn]
457declare -n test_var4=test_var1
458[declare -pr]
459declare -r test_var2=222
460[declare -px]
461declare -x test_var3=333
462## END
463## N-I bash STDOUT:
464[declare -pn]
465declare -- test_var1="111"
466declare -r test_var2="222"
467declare -x test_var3="333"
468declare -n test_var4="test_var1"
469declare -- test_var5="555"
470[declare -pr]
471declare -- test_var1="111"
472declare -r test_var2="222"
473declare -x test_var3="333"
474declare -n test_var4="test_var1"
475declare -- test_var5="555"
476[declare -px]
477declare -- test_var1="111"
478declare -r test_var2="222"
479declare -x test_var3="333"
480declare -n test_var4="test_var1"
481declare -- test_var5="555"
482## END
483## N-I mksh STDOUT:
484[declare -pn]
485[declare -pr]
486[declare -px]
487## END
488
489#### declare -pg
490test_var1=global
491f1() {
492 local test_var1=local
493 {
494 declare -pg
495 } | grep -E '^\[|^\b[^"]*test_var.\b'
496}
497f1
498## STDOUT:
499declare -- test_var1=global
500## END
501## N-I bash STDOUT:
502declare -- test_var1="local"
503## END
504## N-I mksh stdout-json: ""
505## N-I mksh status: 1
506
507#### declare -pg var
508test_var1=global
509f1() {
510 local test_var1=local
511 {
512 declare -pg test_var1
513 } | grep -E '^\[|^\b.*test_var.\b'
514}
515f1
516## STDOUT:
517declare -- test_var1=global
518## END
519## N-I bash STDOUT:
520declare -- test_var1="local"
521## END
522## N-I mksh stdout-json: ""
523## N-I mksh status: 1
524
525#### ble.sh: eval -- "$(declare -p var arr)"
526# This illustrates an example usage of "eval & declare" for exporting
527# multiple variables from $().
528eval -- "$(
529 printf '%s\n' a{1..10} | {
530 sum=0 i=0 arr=()
531 while read line; do
532 ((sum+=${#line},i++))
533 arr[$((i/3))]=$line
534 done
535 declare -p sum arr
536 })"
537echo sum=$sum
538for ((i=0;i<${#arr[@]};i++)); do
539 echo "arr[$i]=${arr[i]}"
540done
541## STDOUT:
542sum=21
543arr[0]=a2
544arr[1]=a5
545arr[2]=a8
546arr[3]=a10
547## END
548## N-I mksh stdout-json: ""
549## N-I mksh status: 1
550
551#### eval -- "$(declare -p arr)" (restore arrays w/ unset elements)
552arr=(1 2 3)
553eval -- "$(arr=(); arr[3]= arr[4]=foo; declare -p arr)"
554for i in {0..4}; do
555 echo "arr[$i]: ${arr[$i]+set ... [}${arr[$i]-unset}${arr[$i]+]}"
556done
557## STDOUT:
558arr[0]: unset
559arr[1]: unset
560arr[2]: unset
561arr[3]: set ... []
562arr[4]: set ... [foo]
563## END
564## N-I mksh stdout-json: ""
565## N-I mksh status: 1
566
567#### typeset -f
568# mksh implement typeset but not declare
569typeset -f myfunc func2
570echo $?
571
572myfunc() { echo myfunc; }
573# This prints the source code.
574typeset -f myfunc func2 > /dev/null
575echo $?
576
577func2() { echo func2; }
578typeset -f myfunc func2 > /dev/null
579echo $?
580## STDOUT:
5811
5821
5830
584## END
585
586#### typeset -p
587var1() { echo func; } # function names are NOT found.
588typeset -p var1 var2 >/dev/null
589echo $?
590
591var1=x
592typeset -p var1 var2 >/dev/null
593echo $?
594
595var2=y
596typeset -p var1 var2 >/dev/null
597echo $?
598## STDOUT:
5991
6001
6010
602## BUG mksh STDOUT:
603# mksh doesn't respect exit codes
6040
6050
6060
607## END
608
609#### typeset -r makes a string readonly
610typeset -r s1='12'
611typeset -r s2='34'
612
613s1='c'
614echo status=$?
615s2='d'
616echo status=$?
617
618s1+='e'
619echo status=$?
620s2+='f'
621echo status=$?
622
623unset s1
624echo status=$?
625unset s2
626echo status=$?
627
628## status: 1
629## stdout-json: ""
630## OK mksh status: 2
631## OK bash status: 0
632## OK bash STDOUT:
633status=1
634status=1
635status=1
636status=1
637status=1
638status=1
639## END
640
641#### typeset -ar makes it readonly
642typeset -a -r array1=(1 2)
643typeset -ar array2=(3 4)
644
645array1=('c')
646echo status=$?
647array2=('d')
648echo status=$?
649
650array1+=('e')
651echo status=$?
652array2+=('f')
653echo status=$?
654
655unset array1
656echo status=$?
657unset array2
658echo status=$?
659
660## status: 1
661## stdout-json: ""
662## OK bash status: 0
663## OK bash STDOUT:
664status=1
665status=1
666status=1
667status=1
668status=1
669status=1
670## END
671## N-I mksh status: 1
672## N-I mksh stdout-json: ""
673
674#### typeset -x makes it exported
675typeset -rx PYTHONPATH=lib/
676printenv.py PYTHONPATH
677## STDOUT:
678lib/
679## END
680
681#### Multiple assignments / array assignments on a line
682a=1 b[0+0]=2 c=3
683echo $a ${b[@]} $c
684## stdout: 1 2 3
685
686#### Env bindings shouldn't contain array assignments
687a=1 b[0]=2 c=3 printenv.py a b c
688## status: 2
689## stdout-json: ""
690## OK bash STDOUT:
6911
692None
6933
694## END
695## OK bash status: 0
696## BUG mksh STDOUT:
6971
6982
6993
700## END
701## OK mksh status: 0
702
703#### syntax error in array assignment
704a=x b[0+]=y c=z
705echo $a $b $c
706## status: 2
707## stdout-json: ""
708## BUG bash stdout: x
709## BUG bash status: 0
710## OK mksh stdout-json: ""
711## OK mksh status: 1
712
713#### declare -g (bash-specific; bash-completion uses it)
714f() {
715 declare -g G=42
716 declare L=99
717
718 declare -Ag dict
719 dict["foo"]=bar
720
721 declare -A localdict
722 localdict["spam"]=Eggs
723
724 # For bash-completion
725 eval 'declare -Ag ev'
726 ev["ev1"]=ev2
727}
728f
729argv.py "$G" "$L"
730argv.py "${dict["foo"]}" "${localdict["spam"]}"
731argv.py "${ev["ev1"]}"
732## STDOUT:
733['42', '']
734['bar', '']
735['ev2']
736## END
737## N-I mksh STDOUT:
738['', '']
739## END
740## N-I mksh status: 1
741
742#### myvar=typeset (another form of dynamic assignment)
743myvar=typeset
744x='a b'
745$myvar x=$x
746echo $x
747## STDOUT:
748a
749## END
750## OK osh STDOUT:
751a b
752## END
753
754#### dynamic array parsing is not allowed
755code='x=(1 2 3)'
756typeset -a "$code" # note: -a flag is required
757echo status=$?
758argv.py "$x"
759## STDOUT:
760status=2
761['']
762## END
763## OK mksh STDOUT:
764status=0
765['(1 2 3)']
766## END
767# bash allows it
768## OK bash STDOUT:
769status=0
770['1']
771## END
772
773#### dynamic flag in array in assign builtin
774typeset b
775b=(unused1 unused2) # this works in mksh
776
777a=(x 'foo=F' 'bar=B')
778typeset -"${a[@]}"
779echo foo=$foo
780echo bar=$bar
781printenv.py foo
782printenv.py bar
783
784# syntax error in mksh! But works in bash and zsh.
785#typeset -"${a[@]}" b=(spam eggs)
786#echo "length of b = ${#b[@]}"
787#echo "b[0]=${b[0]}"
788#echo "b[1]=${b[1]}"
789
790## STDOUT:
791foo=F
792bar=B
793F
794B
795## END
796
797#### typeset +x
798export e=E
799printenv.py e
800typeset +x e=E2
801printenv.py e # no longer exported
802## STDOUT:
803E
804None
805## END
806
807#### typeset +r removes read-only attribute (TODO: documented in bash to do nothing)
808readonly r=r1
809echo r=$r
810
811# clear the readonly flag. Why is this accepted in bash, but doesn't do
812# anything?
813typeset +r r=r2
814echo r=$r
815
816r=r3
817echo r=$r
818
819## status: 0
820## STDOUT:
821r=r1
822r=r2
823r=r3
824## END
825
826# mksh doesn't allow you to unset
827## OK mksh status: 2
828## OK mksh STDOUT:
829r=r1
830## END
831
832# bash doesn't allow you to unset
833## OK bash status: 0
834## OK bash STDOUT:
835r=r1
836r=r1
837r=r1
838## END
839
840
841#### function name with /
842ble/foo() { echo hi; }
843declare -F ble/foo
844echo status=$?
845## STDOUT:
846ble/foo
847status=0
848## END
849## N-I mksh stdout: status=127
850## N-I zsh stdout-json: ""
851## N-I zsh status: 1
852## N-I ash stdout-json: ""
853## N-I ash status: 2
854
855#### invalid var name
856typeset foo/bar
857## status: 1
858
859#### unset and shell funcs
860foo() {
861 echo bar
862}
863
864foo
865
866declare -F
867unset foo
868declare -F
869
870foo
871
872## status: 127
873## STDOUT:
874bar
875declare -f foo
876## END