1 #!/usr/bin/env bash
2
3 #### exec builtin
4 exec echo hi
5 ## stdout: hi
6
7 #### exec builtin with redirects
8 exec 1>&2
9 echo 'to stderr'
10 ## stdout-json: ""
11 ## stderr: to stderr
12
13 #### exec builtin with here doc
14 # This has in a separate file because both code and data can be read from
15 # stdin.
16 $SH spec/builtins-exec-here-doc-helper.sh
17 ## stdout-json: "x=one\ny=two\nDONE\n"
18
19 #### cd and $PWD
20 cd /
21 echo $PWD
22 ## stdout: /
23
24 #### $OLDPWD
25 cd /
26 cd $TMP
27 echo "old: $OLDPWD"
28 env | grep OLDPWD # It's EXPORTED too!
29 cd -
30 ## STDOUT:
31 old: /
32 OLDPWD=/
33 /
34 ## END
35 ## BUG mksh STDOUT:
36 old: /
37 /
38 ## END
39
40 #### pwd
41 cd /
42 pwd
43 ## STDOUT:
44 /
45 ## END
46
47 #### pwd after cd ..
48 dir=$TMP/dir-one/dir-two
49 mkdir -p $dir
50 cd $dir
51 echo $(basename $(pwd))
52 cd ..
53 echo $(basename $(pwd))
54 ## STDOUT:
55 dir-two
56 dir-one
57 ## END
58
59 #### pwd -P
60 tmp=$TMP/builtins-pwd-1
61 mkdir -p $tmp
62 mkdir -p $tmp/symtarg
63 ln -s $tmp/symtarg $tmp/symlink
64 cd $tmp/symlink
65 basename $(pwd -P)
66 cd $tmp
67 rmdir $tmp/symtarg
68 rm $tmp/symlink
69 ## stdout: symtarg
70
71 #### set PWD to something different, invoke pwd
72 dir=/tmp/oil-spec-test/pwd
73 mkdir -p $dir
74 cd $dir
75
76 PWD=foo
77 echo before $PWD
78 pwd
79 echo after $PWD
80 ## STDOUT:
81 before foo
82 /tmp/oil-spec-test/pwd
83 after foo
84 ## END
85
86 #### unset PWD; then pwd
87 dir=/tmp/oil-spec-test/pwd
88 mkdir -p $dir
89 cd $dir
90
91 unset PWD
92 echo [$PWD]
93 pwd
94 echo [$PWD]
95 ## STDOUT:
96 []
97 /tmp/oil-spec-test/pwd
98 []
99 ## END
100
101
102 #### remove pwd dir
103 dir=/tmp/oil-spec-test/pwd
104 mkdir -p $dir
105 cd $dir
106 pwd
107 rmdir $dir
108 echo status=$?
109 pwd
110 echo status=$?
111 ## STDOUT:
112 /tmp/oil-spec-test/pwd
113 status=0
114 /tmp/oil-spec-test/pwd
115 status=0
116 ## END
117 ## OK mksh/osh STDOUT:
118 /tmp/oil-spec-test/pwd
119 status=0
120 status=1
121 ## END
122
123
124 #### Test the current directory after 'cd ..' involving symlinks
125 dir=$TMP/symlinktest
126 mkdir -p $dir
127 cd $dir
128 mkdir -p a/b/c
129 mkdir -p a/b/d
130 ln -s -f a/b/c c > /dev/null
131 cd c
132 cd ..
133 # Expecting a c/ (since we are in symlinktest) but osh gives c d (thinks we are
134 # in b/)
135 ls
136 ## STDOUT:
137 a
138 c
139 ## END
140
141 #### cd with no arguments
142 HOME=$TMP/home
143 mkdir -p $HOME
144 cd
145 test $(pwd) = "$HOME" && echo OK
146 ## stdout: OK
147
148 #### cd to nonexistent dir
149 cd /nonexistent/dir
150 echo status=$?
151 ## stdout: status=1
152 ## OK dash/mksh stdout: status=2
153
154 #### cd away from dir that was deleted
155 dir=$TMP/cd-nonexistent
156 mkdir -p $dir
157 cd $dir
158 rmdir $dir
159 cd $TMP
160 echo $(basename $OLDPWD)
161 echo status=$?
162 ## STDOUT:
163 cd-nonexistent
164 status=0
165 ## END
166
167 #### cd permits double bare dash
168 cd -- /
169 echo $PWD
170 ## stdout: /
171
172 #### cd to symlink with -L and -P
173 targ=$TMP/cd-symtarget
174 lnk=$TMP/cd-symlink
175 mkdir -p $targ
176 ln -s $targ $lnk
177
178 # -L behavior is the default
179 cd $lnk
180 test $PWD = "$TMP/cd-symlink" && echo OK
181
182 cd -L $lnk
183 test $PWD = "$TMP/cd-symlink" && echo OK
184
185 cd -P $lnk
186 test $PWD = "$TMP/cd-symtarget" && echo OK || echo $PWD
187 ## STDOUT:
188 OK
189 OK
190 OK
191 ## END
192
193 #### cd to relative path with -L and -P
194 die() { echo "$@"; exit 1; }
195
196 targ=$TMP/cd-symtarget/subdir
197 lnk=$TMP/cd-symlink
198 mkdir -p $targ
199 ln -s $targ $lnk
200
201 # -L behavior is the default
202 cd $lnk/subdir
203 test $PWD = "$TMP/cd-symlink/subdir" || die "failed"
204 cd ..
205 test $PWD = "$TMP/cd-symlink" && echo OK
206
207 cd $lnk/subdir
208 test $PWD = "$TMP/cd-symlink/subdir" || die "failed"
209 cd -L ..
210 test $PWD = "$TMP/cd-symlink" && echo OK
211
212 cd $lnk/subdir
213 test $PWD = "$TMP/cd-symlink/subdir" || die "failed"
214 cd -P ..
215 test $PWD = "$TMP/cd-symtarget" && echo OK || echo $PWD
216 ## STDOUT:
217 OK
218 OK
219 OK
220 ## END
221
222 #### Exit out of function
223 f() { exit 3; }
224 f
225 exit 4
226 ## status: 3
227
228 #### Exit builtin with invalid arg
229 exit invalid
230 # Rationale: runtime errors are 1
231 ## status: 1
232 ## OK dash/bash status: 2
233
234 #### Exit builtin with too many args
235 # This is a parse error in OSH.
236 exit 7 8 9
237 echo status=$?
238 ## status: 2
239 ## stdout-json: ""
240 ## BUG bash status: 0
241 ## BUG bash stdout: status=1
242 ## BUG dash status: 7
243 ## BUG dash stdout-json: ""
244 ## OK mksh status: 1
245 ## OK mksh stdout-json: ""
246
247 #### time block
248 # bash and mksh work; dash does't.
249 # TODO: osh needs to implement BraceGroup redirect properly.
250 err=_tmp/time-$(basename $SH).txt
251 {
252 time {
253 sleep 0.01
254 sleep 0.02
255 }
256 } 2> $err
257 cat $err | grep --only-matching real
258 # Just check that we found 'real'.
259 # This is fiddly:
260 # | sed -n -E -e 's/.*(0m0\.03).*/\1/'
261 #
262 ## status: 0
263 ## stdout: real
264 ## BUG dash status: 2
265 ## BUG dash stdout-json: ""
266
267 #### time pipeline
268 time echo hi | wc -c
269 ## stdout: 3
270 ## status: 0
271
272 #### shift
273 set -- 1 2 3 4
274 shift
275 echo "$@"
276 shift 2
277 echo "$@"
278 ## stdout-json: "2 3 4\n4\n"
279 ## status: 0
280
281 #### Shifting too far
282 set -- 1
283 shift 2
284 ## status: 1
285 ## OK dash status: 2
286
287 #### Invalid shift argument
288 shift ZZZ
289 ## status: 2
290 ## OK bash status: 1
291 ## BUG mksh status: 0
292
293 #### get umask
294 umask | grep '[0-9]\+' # check for digits
295 ## status: 0
296
297 #### set umask in octal
298 rm -f $TMP/umask-one $TMP/umask-two
299 umask 0002
300 echo one > $TMP/umask-one
301 umask 0022
302 echo two > $TMP/umask-two
303 stat -c '%a' $TMP/umask-one $TMP/umask-two
304 ## status: 0
305 ## stdout-json: "664\n644\n"
306 ## stderr-json: ""
307
308 #### set umask symbolically
309 umask 0002 # begin in a known state for the test
310 rm $TMP/umask-one $TMP/umask-two
311 echo one > $TMP/umask-one
312 umask g-w,o-w
313 echo two > $TMP/umask-two
314 stat -c '%a' $TMP/umask-one $TMP/umask-two
315 ## status: 0
316 ## STDOUT:
317 664
318 644
319 ## END
320 ## stderr-json: ""