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

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