1 #!/bin/bash
2
3 ### cd and $PWD
4 cd /
5 echo $PWD
6 # stdout: /
7
8 ### $OLDPWD
9 cd /
10 cd $TMP
11 echo "old: $OLDPWD"
12 cd -
13 # stdout-json: "old: /\n/\n"
14
15 ### pushd/popd
16 set -o errexit
17 cd /
18 pushd $TMP
19 popd
20 pwd
21 # status: 0
22 # N-I dash/mksh status: 127
23
24 ### Source
25 lib=$TMP/spec-test-lib.sh
26 echo 'LIBVAR=libvar' > $lib
27 . $lib # dash doesn't have source
28 echo $LIBVAR
29 # stdout: libvar
30
31 ### Exit builtin
32 exit 3
33 # status: 3
34
35 ### Exit builtin with invalid arg
36 exit invalid
37 # Rationale: runtime errors are 1
38 # status: 1
39 # OK dash/bash status: 2
40
41 ### Export sets a global variable
42 # Even after you do export -n, it still exists.
43 f() { export GLOBAL=X; }
44 f
45 echo $GLOBAL
46 printenv.py GLOBAL
47 # stdout-json: "X\nX\n"
48
49 ### Export sets a global variable that persists after export -n
50 f() { export GLOBAL=X; }
51 f
52 echo $GLOBAL
53 printenv.py GLOBAL
54 export -n GLOBAL
55 echo $GLOBAL
56 printenv.py GLOBAL
57 # stdout-json: "X\nX\nX\nNone\n"
58 # N-I mksh/dash stdout-json: "X\nX\n"
59
60 ### Export a global variable and unset it
61 f() { export GLOBAL=X; }
62 f
63 echo $GLOBAL
64 printenv.py GLOBAL
65 unset GLOBAL
66 echo $GLOBAL
67 printenv.py GLOBAL
68 # stdout-json: "X\nX\n\nNone\n"
69
70 ### Export existing global variables
71 G1=g1
72 G2=g2
73 export G1 G2
74 printenv.py G1 G2
75 # stdout-json: "g1\ng2\n"
76
77 ### Export existing local variable
78 f() {
79 local L1=local1
80 export L1
81 printenv.py L1
82 }
83 f
84 printenv.py L1
85 # stdout-json: "local1\nNone\n"
86
87 ### Export a local that shadows a global
88 V=global
89 f() {
90 local V=local1
91 export V
92 printenv.py V
93 }
94 f
95 printenv.py V # exported local out of scope; global isn't exported yet
96 export V
97 printenv.py V # now it's exported
98 # stdout-json: "local1\nNone\nglobal\n"
99
100 ### Export a variable before defining it
101 export U
102 U=u
103 printenv.py U
104 # stdout: u
105
106 ### Exporting a parent func variable (dynamic scope)
107 # The algorithm is to walk up the stack and export that one.
108 inner() {
109 export outer_var
110 echo "inner: $outer_var"
111 printenv.py outer_var
112 }
113 outer() {
114 local outer_var=X
115 echo "before inner"
116 printenv.py outer_var
117 inner
118 echo "after inner"
119 printenv.py outer_var
120 }
121 outer
122 # stdout-json: "before inner\nNone\ninner: X\nX\nafter inner\nX\n"
123
124 ### time block
125 # bash and mksh work; dash does't.
126 # TODO: osh needs to implement BraceGroup redirect properly.
127 err=_tmp/time-$(basename $SH).txt
128 {
129 time {
130 sleep 0.01
131 sleep 0.02
132 }
133 } 2> $err
134 cat $err | grep --only-matching real
135 # Just check that we found 'real'.
136 # This is fiddly:
137 # | sed -n -E -e 's/.*(0m0\.03).*/\1/'
138 #
139 # status: 0
140 # stdout: real
141 # BUG dash status: 2
142 # BUG dash stdout-json: ""
143
144 ### time pipeline
145 time echo hi | wc -c
146 # stdout: 3
147 # status: 0
148
149 ### shift
150 set -- 1 2 3 4
151 shift
152 echo "$@"
153 shift 2
154 echo "$@"
155 # stdout-json: "2 3 4\n4\n"
156 # status: 0
157
158 ### Shifting too far
159 set -- 1
160 shift 2
161 # status: 1
162 # OK dash status: 2
163
164 ### Invalid shift argument
165 shift ZZZ
166 # status: 1
167 # OK dash status: 2
168 # BUG mksh status: 0