OILS / spec / assign-extended.test.sh View on Github | oilshell.org

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