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