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