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

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