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)
10 f() {
11 local -a array=(x y z)
12 argv.py "${array[@]}"
13 }
14 f
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)
21 declare -a array=(x y z)
22 argv.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)
28 a[1 * 1]=x a[ 1 + 2 ]=z
29 echo status=$?
30 argv.py "${a[@]}"
31 ## STDOUT:
32 status=0
33 ['x', 'z']
34 ## END
35 ## N-I osh STDOUT:
36 status=127
37 []
38 ## END
39
40 #### declare -f exit code indicates function existence
41 func2=x # var names are NOT found
42 declare -f myfunc func2
43 echo $?
44
45 myfunc() { echo myfunc; }
46 # This prints the source code.
47 declare -f myfunc func2 > /dev/null
48 echo $?
49
50 func2() { echo func2; }
51 declare -f myfunc func2 > /dev/null
52 echo $?
53 ## STDOUT:
54 1
55 1
56 0
57 ## END
58 ## N-I mksh STDOUT:
59 127
60 127
61 127
62 ## END
63
64 #### declare -F prints function names
65 add () { expr 4 + 4; }
66 div () { expr 6 / 2; }
67 ek () { echo hello; }
68 __ec () { echo hi; }
69 _ab () { expr 10 % 3; }
70
71 declare -F
72 ## STDOUT:
73 declare -f __ec
74 declare -f _ab
75 declare -f add
76 declare -f div
77 declare -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
83 case $SH in mksh) exit ;; esac
84
85 source $REPO_ROOT/spec/testdata/bash-source-2.sh
86
87 shopt -s extdebug
88
89 add () { expr 4 + 4; }
90
91 declare -F
92 echo
93
94 declare -F add
95 # in bash-source-2
96 declare -F g | sed "s;$REPO_ROOT;ROOT;g"
97
98 ## STDOUT:
99 declare -f add
100 declare -f g
101
102 add 7 main
103 g 3 ROOT/spec/testdata/bash-source-2.sh
104 ## END
105 ## N-I mksh stdout-json: ""
106
107 #### declare -p var (exit status)
108 var1() { echo func; } # function names are NOT found.
109 declare -p var1 var2 >/dev/null
110 echo $?
111
112 var1=x
113 declare -p var1 var2 >/dev/null
114 echo $?
115
116 var2=y
117 declare -p var1 var2 >/dev/null
118 echo $?
119 ## STDOUT:
120 1
121 1
122 0
123 ## N-I mksh STDOUT:
124 127
125 127
126 127
127 ## END
128
129 #### declare
130 test_var1=111
131 readonly test_var2=222
132 export test_var3=333
133 declare -n test_var4=test_var1
134 f1() {
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 }
147 f1
148 ## STDOUT:
149 [declare]
150 test_var1=111
151 test_var2=222
152 test_var3=333
153 test_var4=test_var1
154 test_var5=555
155 [readonly]
156 declare -r test_var2=222
157 [export]
158 declare -x test_var3=333
159 [local]
160 test_var5=555
161 ## END
162 ## OK bash STDOUT:
163 [declare]
164 test_var1=111
165 test_var2=222
166 test_var3=333
167 test_var4=test_var1
168 test_var5=555
169 [readonly]
170 declare -r test_var2="222"
171 [export]
172 declare -x test_var3="333"
173 [local]
174 test_var5=555
175 ## END
176 ## N-I mksh STDOUT:
177 [declare]
178 [readonly]
179 test_var2
180 [export]
181 test_var3
182 [local]
183 typeset test_var1
184 typeset -r test_var2
185 typeset -x test_var3
186 typeset 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.
192 test_var1=111
193 readonly test_var2=222
194 export test_var3=333
195 declare -n test_var4=test_var1
196 f1() {
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 }
209 f1
210 ## STDOUT:
211 [declare]
212 declare -- test_var1=111
213 declare -r test_var2=222
214 declare -x test_var3=333
215 declare -n test_var4=test_var1
216 declare -- test_var5=555
217 [readonly]
218 declare -r test_var2=222
219 [export]
220 declare -x test_var3=333
221 [local]
222 declare -- test_var5=555
223 ## END
224 ## BUG bash STDOUT:
225 [declare]
226 declare -- test_var1="111"
227 declare -r test_var2="222"
228 declare -x test_var3="333"
229 declare -n test_var4="test_var1"
230 declare -- test_var5="555"
231 [readonly]
232 declare -r test_var2="222"
233 [export]
234 declare -x test_var3="333"
235 [local]
236 test_var5=555
237 ## END
238 ## N-I mksh STDOUT:
239 [declare]
240 [readonly]
241 readonly test_var2=222
242 [export]
243 export test_var3=333
244 [local]
245 typeset test_var1=111
246 typeset -r test_var2=222
247 typeset -x test_var3=333
248 typeset 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!
254 case $SH in bash*|mksh) exit ;; esac
255
256 unquoted='foo'
257 sq='foo bar'
258 bash1=$'\x1f' # ASCII control char
259 bash2=$'\xfe\xff' # Invalid UTF-8
260
261 s1=$unquoted
262 s2=$sq
263 s3=$bash1
264 s4=$bash2
265
266 declare -a a=("$unquoted" "$sq" "$bash1" "$bash2")
267 declare -A A=(["$unquoted"]="$sq" ["$bash1"]="$bash2")
268
269 #echo lengths ${#s1} ${#s2} ${#s3} ${#s4} ${#a[@]} ${#A[@]}
270
271 declare -p s1 s2 s3 s4 a A | tee tmp.bash
272
273 echo ---
274
275 bash -c 'source tmp.bash; echo "$s1 $s2"; echo -n "$s3" "$s4" | od -A n -t x1'
276 echo bash=$?
277
278 ## STDOUT:
279 declare -- s1=foo
280 declare -- s2='foo bar'
281 declare -- s3=$'\u001f'
282 declare -- s4=$'\xfe\xff'
283 declare -a a=(foo 'foo bar' $'\u001f' $'\xfe\xff')
284 declare -A A=([$'\u001f']=$'\xfe\xff' ['foo']='foo bar')
285 ---
286 foo foo bar
287 1f 20 fe ff
288 bash=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
300 test_var1=111
301 readonly test_var2=222
302 export test_var3=333
303 declare -n test_var4=test_var1
304 f1() {
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 }
317 f1
318 ## STDOUT:
319 [declare]
320 declare -- test_var1=111
321 declare -r test_var2=222
322 declare -x test_var3=333
323 declare -n test_var4=test_var1
324 declare -- test_var5=555
325 [readonly]
326 declare -r test_var2=222
327 [export]
328 declare -x test_var3=333
329 [local]
330 declare -- test_var5=555
331 ## END
332 ## BUG bash STDOUT:
333 [declare]
334 declare -- test_var1="111"
335 declare -r test_var2="222"
336 declare -x test_var3="333"
337 declare -n test_var4="test_var1"
338 declare -- 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
349 test_arr1=()
350 declare -a test_arr2=()
351 declare -A test_arr3=()
352 test_arr4=(1 2 3)
353 declare -a test_arr5=(1 2 3)
354 declare -A test_arr6=(['a']=1 ['b']=2 ['c']=3)
355 test_arr7=()
356 test_arr7[3]=foo
357 declare -p test_arr{1..7}
358 ## STDOUT:
359 declare -a test_arr1=()
360 declare -a test_arr2=()
361 declare -A test_arr3=()
362 declare -a test_arr4=(1 2 3)
363 declare -a test_arr5=(1 2 3)
364 declare -A test_arr6=(['a']=1 ['b']=2 ['c']=3)
365 declare -a test_arr7=(); test_arr7[3]=foo
366 ## END
367 ## OK bash STDOUT:
368 declare -a test_arr1=()
369 declare -a test_arr2=()
370 declare -A test_arr3=()
371 declare -a test_arr4=([0]="1" [1]="2" [2]="3")
372 declare -a test_arr5=([0]="1" [1]="2" [2]="3")
373 declare -A test_arr6=([a]="1" [b]="2" [c]="3" )
374 declare -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
380 case $SH in (mksh) exit 0; esac
381
382 declare -p foo=bar
383 echo status=$?
384
385 a=b
386 declare -p a foo=bar > tmp.txt
387 echo status=$?
388 sed 's/"//g' tmp.txt # don't care about quotes
389 ## STDOUT:
390 status=1
391 status=1
392 declare -- a=b
393 ## END
394 ## N-I mksh stdout-json: ""
395
396 #### declare -pnrx
397 test_var1=111
398 readonly test_var2=222
399 export test_var3=333
400 declare -n test_var4=test_var1
401 f1() {
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 }
412 f1
413 ## STDOUT:
414 [declare -pn]
415 declare -n test_var4=test_var1
416 [declare -pr]
417 declare -r test_var2=222
418 [declare -px]
419 declare -x test_var3=333
420 ## END
421 ## OK bash STDOUT:
422 [declare -pn]
423 declare -n test_var4="test_var1"
424 [declare -pr]
425 declare -r test_var2="222"
426 [declare -px]
427 declare -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
436 declare -a test_var6=()
437 declare -A test_var7=()
438 f1() {
439 {
440 echo '[declare -pa]'
441 declare -pa
442 echo '[declare -pA]'
443 declare -pA
444 } | grep -E '^\[|^\b.*test_var.\b'
445 }
446 f1
447 ## STDOUT:
448 [declare -pa]
449 declare -a test_var6=()
450 [declare -pA]
451 declare -A test_var7=()
452 ## END
453 ## OK bash STDOUT:
454 [declare -pa]
455 declare -a test_var6=()
456 [declare -pA]
457 declare -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.
465 test_var1=111
466 readonly test_var2=222
467 export test_var3=333
468 declare -n test_var4=test_var1
469 f1() {
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 }
480 f1
481 ## STDOUT:
482 [declare -pn]
483 declare -n test_var4=test_var1
484 [declare -pr]
485 declare -r test_var2=222
486 [declare -px]
487 declare -x test_var3=333
488 ## END
489 ## N-I bash STDOUT:
490 [declare -pn]
491 declare -- test_var1="111"
492 declare -r test_var2="222"
493 declare -x test_var3="333"
494 declare -n test_var4="test_var1"
495 declare -- test_var5="555"
496 [declare -pr]
497 declare -- test_var1="111"
498 declare -r test_var2="222"
499 declare -x test_var3="333"
500 declare -n test_var4="test_var1"
501 declare -- test_var5="555"
502 [declare -px]
503 declare -- test_var1="111"
504 declare -r test_var2="222"
505 declare -x test_var3="333"
506 declare -n test_var4="test_var1"
507 declare -- 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
516 test_var1=global
517 f1() {
518 local test_var1=local
519 {
520 declare -pg
521 } | grep -E '^\[|^\b[^"]*test_var.\b'
522 }
523 f1
524 ## STDOUT:
525 declare -- test_var1=global
526 ## END
527 ## N-I bash STDOUT:
528 declare -- test_var1="local"
529 ## END
530 ## N-I mksh stdout-json: ""
531 ## N-I mksh status: 1
532
533 #### declare -pg var
534 test_var1=global
535 f1() {
536 local test_var1=local
537 {
538 declare -pg test_var1
539 } | grep -E '^\[|^\b.*test_var.\b'
540 }
541 f1
542 ## STDOUT:
543 declare -- test_var1=global
544 ## END
545 ## N-I bash STDOUT:
546 declare -- 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 $().
554 eval -- "$(
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 })"
563 echo sum=$sum
564 for ((i=0;i<${#arr[@]};i++)); do
565 echo "arr[$i]=${arr[i]}"
566 done
567 ## STDOUT:
568 sum=21
569 arr[0]=a2
570 arr[1]=a5
571 arr[2]=a8
572 arr[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)
578 arr=(1 2 3)
579 eval -- "$(arr=(); arr[3]= arr[4]=foo; declare -p arr)"
580 for i in {0..4}; do
581 echo "arr[$i]: ${arr[$i]+set ... [}${arr[$i]-unset}${arr[$i]+]}"
582 done
583 ## STDOUT:
584 arr[0]: unset
585 arr[1]: unset
586 arr[2]: unset
587 arr[3]: set ... []
588 arr[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
595 typeset -f myfunc func2
596 echo $?
597
598 myfunc() { echo myfunc; }
599 # This prints the source code.
600 typeset -f myfunc func2 > /dev/null
601 echo $?
602
603 func2() { echo func2; }
604 typeset -f myfunc func2 > /dev/null
605 echo $?
606 ## STDOUT:
607 1
608 1
609 0
610 ## END
611
612 #### typeset -p
613 var1() { echo func; } # function names are NOT found.
614 typeset -p var1 var2 >/dev/null
615 echo $?
616
617 var1=x
618 typeset -p var1 var2 >/dev/null
619 echo $?
620
621 var2=y
622 typeset -p var1 var2 >/dev/null
623 echo $?
624 ## STDOUT:
625 1
626 1
627 0
628 ## BUG mksh STDOUT:
629 # mksh doesn't respect exit codes
630 0
631 0
632 0
633 ## END
634
635 #### typeset -r makes a string readonly
636 typeset -r s1='12'
637 typeset -r s2='34'
638
639 s1='c'
640 echo status=$?
641 s2='d'
642 echo status=$?
643
644 s1+='e'
645 echo status=$?
646 s2+='f'
647 echo status=$?
648
649 unset s1
650 echo status=$?
651 unset s2
652 echo status=$?
653
654 ## status: 1
655 ## stdout-json: ""
656 ## OK mksh status: 2
657 ## OK bash status: 0
658 ## OK bash STDOUT:
659 status=1
660 status=1
661 status=1
662 status=1
663 status=1
664 status=1
665 ## END
666
667 #### typeset -ar makes it readonly
668 typeset -a -r array1=(1 2)
669 typeset -ar array2=(3 4)
670
671 array1=('c')
672 echo status=$?
673 array2=('d')
674 echo status=$?
675
676 array1+=('e')
677 echo status=$?
678 array2+=('f')
679 echo status=$?
680
681 unset array1
682 echo status=$?
683 unset array2
684 echo status=$?
685
686 ## status: 1
687 ## stdout-json: ""
688 ## OK bash status: 0
689 ## OK bash STDOUT:
690 status=1
691 status=1
692 status=1
693 status=1
694 status=1
695 status=1
696 ## END
697 ## N-I mksh status: 1
698 ## N-I mksh stdout-json: ""
699
700 #### typeset -x makes it exported
701 typeset -rx PYTHONPATH=lib/
702 printenv.py PYTHONPATH
703 ## STDOUT:
704 lib/
705 ## END
706
707 #### Multiple assignments / array assignments on a line
708 a=1 b[0+0]=2 c=3
709 echo $a ${b[@]} $c
710 ## stdout: 1 2 3
711
712 #### Env bindings shouldn't contain array assignments
713 a=1 b[0]=2 c=3 printenv.py a b c
714 ## status: 2
715 ## stdout-json: ""
716 ## OK bash STDOUT:
717 1
718 None
719 3
720 ## END
721 ## OK bash status: 0
722 ## BUG mksh STDOUT:
723 1
724 2
725 3
726 ## END
727 ## BUG mksh status: 0
728
729 #### syntax error in array assignment
730 a=x b[0+]=y c=z
731 echo $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)
740 f() {
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 }
754 f
755 argv.py "$G" "$L"
756 argv.py "${dict["foo"]}" "${localdict["spam"]}"
757 argv.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)
769 myvar=typeset
770 x='a b'
771 $myvar x=$x
772 echo $x
773 ## STDOUT:
774 a
775 ## END
776 ## OK osh STDOUT:
777 a b
778 ## END
779
780 #### dynamic array parsing is not allowed
781 code='x=(1 2 3)'
782 typeset -a "$code" # note: -a flag is required
783 echo status=$?
784 argv.py "$x"
785 ## STDOUT:
786 status=2
787 ['']
788 ## END
789 ## OK mksh STDOUT:
790 status=0
791 ['(1 2 3)']
792 ## END
793 # bash allows it
794 ## OK bash STDOUT:
795 status=0
796 ['1']
797 ## END
798
799 #### dynamic flag in array in assign builtin
800 typeset b
801 b=(unused1 unused2) # this works in mksh
802
803 a=(x 'foo=F' 'bar=B')
804 typeset -"${a[@]}"
805 echo foo=$foo
806 echo bar=$bar
807 printenv.py foo
808 printenv.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:
817 foo=F
818 bar=B
819 F
820 B
821 ## END
822
823 #### typeset +x
824 export e=E
825 printenv.py e
826 typeset +x e=E2
827 printenv.py e # no longer exported
828 ## STDOUT:
829 E
830 None
831 ## END
832
833 #### typeset +r removes read-only attribute (TODO: documented in bash to do nothing)
834 readonly r=r1
835 echo r=$r
836
837 # clear the readonly flag. Why is this accepted in bash, but doesn't do
838 # anything?
839 typeset +r r=r2
840 echo r=$r
841
842 r=r3
843 echo r=$r
844
845 ## status: 0
846 ## STDOUT:
847 r=r1
848 r=r2
849 r=r3
850 ## END
851
852 # mksh doesn't allow you to unset
853 ## OK mksh status: 2
854 ## OK mksh STDOUT:
855 r=r1
856 ## END
857
858 # bash doesn't allow you to unset
859 ## OK bash status: 0
860 ## OK bash STDOUT:
861 r=r1
862 r=r1
863 r=r1
864 ## END
865
866
867 #### function name with /
868 ble/foo() { echo hi; }
869 declare -F ble/foo
870 echo status=$?
871 ## STDOUT:
872 ble/foo
873 status=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
882 typeset foo/bar
883 ## status: 1
884
885 #### unset and shell funcs
886 foo() {
887 echo bar
888 }
889
890 foo
891
892 declare -F
893 unset foo
894 declare -F
895
896 foo
897
898 ## status: 127
899 ## STDOUT:
900 bar
901 declare -f foo
902 ## END
903 ## N-I mksh status: 0
904 ## N-I mksh STDOUT:
905 bar
906 bar
907 ## END