1 ## compare_shells: dash bash mksh zsh
2 ## oils_failures_allowed: 2
3 ## oils_cpp_failures_allowed: 2
4
5 #### exec builtin
6 exec echo hi
7 ## stdout: hi
8
9 #### exec builtin with redirects
10 exec 1>&2
11 echo 'to stderr'
12 ## stdout-json: ""
13 ## stderr: to stderr
14
15 #### exec builtin with here doc
16 # This has in a separate file because both code and data can be read from
17 # stdin.
18 $SH $REPO_ROOT/spec/bin/builtins-exec-here-doc-helper.sh
19 ## STDOUT:
20 x=one
21 y=two
22 DONE
23 ## END
24
25 #### exec builtin accepts --
26 exec -- echo hi
27 ## STDOUT:
28 hi
29 ## END
30 ## BUG dash status: 127
31 ## BUG dash stdout-json: ""
32
33 #### exec -- 2>&1
34 exec -- 3>&1
35 echo stdout 1>&3
36 ## STDOUT:
37 stdout
38 ## END
39 ## BUG dash status: 127
40 ## BUG dash stdout-json: ""
41 ## BUG mksh status: -11
42 ## BUG mksh stdout-json: ""
43
44 #### Exit out of function
45 f() { exit 3; }
46 f
47 exit 4
48 ## status: 3
49
50 #### Exit builtin with invalid arg
51 exit invalid
52 # Rationale: runtime errors are 1
53 ## status: 1
54 ## OK dash/bash status: 2
55 ## BUG zsh status: 0
56
57 #### Exit builtin with too many args
58 # This is a parse error in OSH.
59 exit 7 8 9
60 echo status=$?
61 ## status: 2
62 ## stdout-json: ""
63 ## BUG bash/zsh status: 0
64 ## BUG bash/zsh stdout: status=1
65 ## BUG dash status: 7
66 ## BUG dash stdout-json: ""
67 ## OK mksh status: 1
68 ## OK mksh stdout-json: ""
69
70 #### time with brace group argument
71
72 err=time-$(basename $SH).txt
73 {
74 time {
75 sleep 0.01
76 sleep 0.02
77 }
78 } 2> $err
79
80 grep --only-matching user $err
81 echo result=$?
82
83 # Regression: check fractional seconds
84 gawk '
85 BEGIN { ok = 0 }
86 match( $0, /\.([0-9]+)/, m) {
87 if (m[1] > 0) { # check fractional seconds
88 ok = 1
89 }
90 }
91 END { if (ok) { print "non-zero" } }
92 ' $err
93
94 ## status: 0
95 ## STDOUT:
96 user
97 result=0
98 non-zero
99 ## END
100
101 # time doesn't accept a block?
102 ## BUG zsh STDOUT:
103 result=1
104 ## END
105
106 # dash doesn't have time keyword
107 ## N-I dash status: 2
108 ## N-I dash stdout-json: ""
109
110
111 #### get umask
112 umask | grep '[0-9]\+' # check for digits
113 ## status: 0
114
115 #### set umask in octal
116 rm -f $TMP/umask-one $TMP/umask-two
117 umask 0002
118 echo one > $TMP/umask-one
119 umask 0022
120 echo two > $TMP/umask-two
121 stat -c '%a' $TMP/umask-one $TMP/umask-two
122 ## status: 0
123 ## STDOUT:
124 664
125 644
126 ## END
127 ## stderr-json: ""
128
129 #### set umask symbolically
130 umask 0002 # begin in a known state for the test
131 rm -f $TMP/umask-one $TMP/umask-two
132 echo one > $TMP/umask-one
133 umask g-w,o-w
134 echo two > $TMP/umask-two
135 stat -c '%a' $TMP/umask-one $TMP/umask-two
136 ## status: 0
137 ## STDOUT:
138 664
139 644
140 ## END
141 ## stderr-json: ""
142
143 #### ulimit with no flags is like -f
144
145 ulimit > no-flags.txt
146 echo status=$?
147
148 ulimit -f > f.txt
149 echo status=$?
150
151 diff -u no-flags.txt f.txt
152 echo diff=$?
153
154 # Print everything
155 # ulimit -a
156
157 ## STDOUT:
158 status=0
159 status=0
160 diff=0
161 ## END
162
163
164 #### ulimit too many args
165
166 ulimit 1 2
167 if test $? -ne 0; then
168 echo pass
169 else
170 echo fail
171 fi
172
173 #ulimit -f
174
175 ## STDOUT:
176 pass
177 ## END
178
179 ## BUG bash/zsh STDOUT:
180 fail
181 ## END
182
183
184 #### ulimit negative flag
185
186 ulimit -f
187
188 # interpreted as a flag
189 ulimit -f -42
190 if test $? -ne 0; then
191 echo pass
192 else
193 echo fail
194 fi
195
196 ## STDOUT:
197 unlimited
198 pass
199 ## END
200
201 #### ulimit negative arg
202
203 ulimit -f
204
205 # an arg
206 ulimit -f -- -42
207 if test $? -ne 0; then
208 echo pass
209 else
210 echo fail
211 fi
212
213 ## STDOUT:
214 unlimited
215 pass
216 ## END
217
218 ## BUG mksh STDOUT:
219 unlimited
220 fail
221 ## END
222
223
224 #### ulimit -a doesn't take arg
225 case $SH in bash) exit ;; esac
226
227 ulimit -a 42
228 if test $? -ne 0; then
229 echo 'failure that was expected'
230 fi
231
232 ## STDOUT:
233 failure that was expected
234 ## END
235 ## BUG bash STDOUT:
236 ## END
237
238
239 #### ulimit doesn't accept multiple flags - reduce confusion between shells
240
241 # - bash, zsh, busybox ash accept multiple "commands", which requires custom
242 # flag parsing, like
243
244 # ulimit -f 999 -n
245 # ulimit -f 999 -n 888
246 #
247 # - dash and mksh accept a single ARG
248 #
249 # we want to make it clear we're like the latter
250
251 # can't print all and -f
252 ulimit -f -a >/dev/null
253 echo status=$?
254
255 ulimit -f -n >/dev/null
256 echo status=$?
257
258 ulimit -f -n 999 >/dev/null
259 echo status=$?
260
261 ## STDOUT:
262 status=2
263 status=2
264 status=2
265 ## END
266
267 ## BUG dash/bash/mksh STDOUT:
268 status=0
269 status=0
270 status=0
271 ## END
272
273 # zsh is better - it checks that -a and -f are exclusive
274
275 ## BUG zsh STDOUT:
276 status=1
277 status=0
278 status=0
279 ## END
280
281
282 #### YSH readability: ulimit --all the same as ulimit -a
283
284 case $SH in bash|dash|mksh|zsh) exit ;; esac
285
286 ulimit -a > short.txt
287 ulimit --all > long.txt
288
289 wc -l short.txt long.txt
290
291 diff -u short.txt long.txt
292 echo status=$?
293
294 ## STDOUT:
295 8 short.txt
296 8 long.txt
297 16 total
298 status=0
299 ## END
300
301 ## N-I bash/dash/mksh/zsh STDOUT:
302 ## END
303
304 #### ulimit accepts 'unlimited'
305
306 for arg in zz unlimited; do
307 echo " arg $arg"
308 ulimit -f
309 echo status=$?
310 ulimit -f $arg
311 if test $? -ne 0; then
312 echo 'FAILED'
313 fi
314 echo
315 done
316 ## STDOUT:
317 arg zz
318 unlimited
319 status=0
320 FAILED
321
322 arg unlimited
323 unlimited
324 status=0
325
326 ## END
327
328
329 #### ulimit of 2**32, 2**31 (int overflow)
330
331 echo -n 'one '; ulimit -f
332
333
334 ulimit -f $(( 1 << 32 ))
335
336 echo -n 'two '; ulimit -f
337
338
339 # mksh fails because it overflows signed int, turning into negative number
340 ulimit -f $(( 1 << 31 ))
341
342 echo -n 'three '; ulimit -f
343
344 ## STDOUT:
345 one unlimited
346 two 4294967296
347 three 2147483648
348 ## END
349 ## BUG mksh STDOUT:
350 one unlimited
351 two 1
352 three 1
353 ## END
354
355
356 #### ulimit that is 64 bits
357
358 # no 64-bit integers
359 case $SH in mksh) exit ;; esac
360
361 echo -n 'before '; ulimit -f
362
363 # 1 << 63 overflows signed int
364
365 # 512 is 1 << 9, so make it 62-9 = 53 bits
366
367 lim=$(( 1 << 53 ))
368 #echo $lim
369
370 # bash says this is out of range
371 ulimit -f $lim
372
373 echo -n 'after '; ulimit -f
374
375 ## STDOUT:
376 before unlimited
377 after 9007199254740992
378 ## END
379
380 ## BUG mksh STDOUT:
381 ## END
382
383
384 #### arg that would overflow 64 bits is detected
385
386 # no 64-bit integers
387 case $SH in mksh) exit ;; esac
388
389 echo -n 'before '; ulimit -f
390
391 # 1 << 63 overflows signed int
392
393 lim=$(( (1 << 62) + 1 ))
394 #echo lim=$lim
395
396 # bash detects that this is out of range
397 # so does osh-cpp, but not osh-cpython
398
399 ulimit -f $lim
400 echo -n 'after '; ulimit -f
401
402 ## STDOUT:
403 before unlimited
404 after unlimited
405 ## END
406
407 ## BUG dash/zsh STDOUT:
408 before unlimited
409 after 1
410 ## END
411
412 ## BUG mksh STDOUT:
413 ## END
414
415
416 #### ulimit -f 1 prevents files larger 512 bytes
417 trap - XFSZ # don't handle this
418
419 rm -f err.txt
420 touch err.txt
421
422 bytes() {
423 local n=$1
424 local st=0
425 for i in $(seq $n); do
426 echo -n x
427 st=$?
428 if test $st -ne 0; then
429 echo "ERROR: echo failed with status $st" >> err.txt
430 fi
431 done
432 }
433
434 ulimit -f 1
435
436 bytes 512 > ok.txt
437 echo 512 status=$?
438
439 bytes 513 > too-big.txt
440 echo 513 status=$?
441 echo
442
443 wc --bytes ok.txt too-big.txt
444 echo
445
446 cat err.txt
447
448 ## status: -25
449 ## STDOUT:
450 512 status=0
451 ## END
452
453 ## OK disabledosh status: 0
454 ## OK disabledosh STDOUT:
455 512 status=0
456 513 status=0
457
458 512 ok.txt
459 512 too-big.txt
460 1024 total
461
462 ERROR: echo failed with status 1
463 ## END
464
465 ## BUG bash status: 0
466 ## BUG bash STDOUT:
467 512 status=0
468 513 status=0
469
470 512 ok.txt
471 513 too-big.txt
472 1025 total
473
474 ## END
475
476 #### write big file with ulimit
477
478 # I think this will test write() errors, rather than the final flush() error
479 # (which is currently skipped by C++
480
481 { echo 'ulimit -f 1'
482 # More than 8 KiB may cause a flush()
483 python2 -c 'print("echo " + "X"*9000 + " >out.txt")'
484 echo 'echo inner=$?'
485 } > big.sh
486
487 $SH big.sh
488 echo outer=$?
489
490 ## STDOUT:
491 outer=153
492 ## END
493
494 # not sure why this is different
495 ## OK osh STDOUT:
496 inner=1
497 outer=0
498 ## END
499
500
501 #### ulimit -S for soft limit (default), -H for hard limit
502 case $SH in dash|zsh) exit ;; esac
503
504 # Note: ulimit -n -S 1111 is OK in osh/dash/mksh, but not bash/zsh
505 # Mus be ulimit -S -n 1111
506
507 show_state() {
508 local msg=$1
509 echo "$msg"
510 echo -n ' '; ulimit -S -t
511 echo -n ' '; ulimit -H -t
512 echo
513 }
514
515 show_state 'init'
516
517 ulimit -S -t 123456
518 show_state '-S'
519
520 ulimit -H -t 123457
521 show_state '-H'
522
523 ulimit -t 123455
524 show_state 'no flag'
525
526 echo 'GET'
527
528 ulimit -S -t 123454
529 echo -n ' '; ulimit -t
530 echo -n ' '; ulimit -S -t
531 echo -n ' '; ulimit -H -t
532
533 ## STDOUT:
534 init
535 unlimited
536 unlimited
537
538 -S
539 123456
540 unlimited
541
542 -H
543 123456
544 123457
545
546 no flag
547 123455
548 123455
549
550 GET
551 123454
552 123454
553 123455
554 ## END
555
556 ## BUG dash/zsh STDOUT:
557 ## END
558
559 #### Changing resource limit is denied
560
561 # Not sure why these don't work
562 case $SH in dash|mksh) exit ;; esac
563
564
565 flag=-t
566
567 ulimit -S -H $flag 100
568 echo both=$?
569
570 ulimit -S $flag 90
571 echo soft=$?
572
573 ulimit -S $flag 95
574 echo soft=$?
575
576 ulimit -S $flag 105
577 if test $? -ne 0; then
578 echo soft OK
579 else
580 echo soft fail
581 fi
582
583 ulimit -H $flag 200
584 if test $? -ne 0; then
585 echo hard OK
586 else
587 echo hard fail
588 fi
589
590 ## STDOUT:
591 both=0
592 soft=0
593 soft=0
594 soft OK
595 hard OK
596 ## END
597
598 ## BUG dash/mksh STDOUT:
599 ## END
600
601 #### ulimit -n limits file descriptors
602
603 # OSH bug
604 # https://oilshell.zulipchat.com/#narrow/channel/502349-osh/topic/alpine.20build.20failures.20-.20make.20-.20ulimit.20-n.2064/with/519691301
605
606 $SH -c 'ulimit -n 64; echo hi >out'
607 echo status=$?
608
609 $SH -c 'ulimit -n 0; echo hi >out'
610 echo status=$?
611
612 ## STDOUT:
613 status=0
614 status=1
615 ## END
616
617 ## OK dash STDOUT:
618 status=0
619 status=2
620 ## END