OILS / spec / assign-extended.test.sh View on Github | oils.pub

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