1 ## compare_shells: bash dash mksh zsh ash
2 ## oils_failures_allowed: 0
3
4 # TODO: case #25 need this locally, but not in CI?
5 # oils_cpp_failures_allowed: 1
6
7 #### echo keyword
8 echo done
9 ## stdout: done
10
11 #### if/else
12 if false; then
13 echo THEN
14 else
15 echo ELSE
16 fi
17 ## stdout: ELSE
18
19 #### Turn an array into an integer.
20 a=(1 2 3)
21 (( a = 42 ))
22 echo $a
23 ## stdout: 42
24 ## N-I dash/ash stdout-json: ""
25 ## N-I dash/ash status: 2
26
27
28 #### assign readonly -- one line
29 readonly x=1; x=2; echo hi
30 ## status: 1
31 ## OK dash/mksh/ash status: 2
32 ## STDOUT:
33 ## END
34
35 #### assign readonly -- multiple lines
36 readonly x=1
37 x=2
38 echo hi
39 ## status: 1
40 ## OK dash/mksh/ash status: 2
41 ## STDOUT:
42 ## END
43 ## BUG bash status: 0
44 ## BUG bash STDOUT:
45 hi
46 ## END
47
48 #### assign readonly -- multiple lines -- set -o posix
49 set -o posix
50 readonly x=1
51 x=2
52 echo hi
53 ## status: 1
54 ## OK dash/mksh/ash status: 2
55 ## STDOUT:
56 ## END
57
58 #### unset readonly -- one line
59 readonly x=1; unset x; echo hi
60 ## STDOUT:
61 hi
62 ## END
63 ## OK dash/ash status: 2
64 ## OK zsh status: 1
65 ## OK dash/ash stdout-json: ""
66 ## OK zsh stdout-json: ""
67
68 #### unset readonly -- multiple lines
69 readonly x=1
70 unset x
71 echo hi
72 ## OK dash/ash status: 2
73 ## OK zsh status: 1
74 ## OK dash/ash stdout-json: ""
75 ## OK zsh stdout-json: ""
76
77 #### First word like foo$x() and foo$[1+2] (regression)
78
79 # Problem: $x() func call broke this error message
80 foo$identity('z')
81
82 foo$[1+2]
83
84 echo DONE
85
86 ## status: 2
87 ## OK mksh/zsh status: 1
88 ## STDOUT:
89 ## END
90
91 #### Function names
92 foo$x() {
93 echo hi
94 }
95
96 foo $x() {
97 echo hi
98 }
99
100 ## status: 2
101 ## OK mksh/zsh status: 1
102 ## BUG zsh status: 0
103 ## STDOUT:
104 ## END
105
106
107 #### file with NUL byte
108 echo -e 'echo one \0 echo two' > tmp.sh
109 $SH tmp.sh
110 ## STDOUT:
111 one echo two
112 ## END
113 ## OK osh STDOUT:
114 one
115 ## END
116 ## N-I dash stdout-json: ""
117 ## N-I dash status: 127
118 ## OK bash stdout-json: ""
119 ## OK bash status: 126
120 ## OK zsh stdout-json: "one \u0000echo two\n"
121
122 #### fastlex: PS1 format string that's incomplete / with NUL byte
123 case $SH in bash) exit ;; esac
124
125 x=$'\\D{%H:%M' # leave off trailing }
126 echo x=${x@P}
127
128 ## STDOUT:
129 x=\D{%H:%M
130 ## END
131
132 # bash just ignores the missing }
133 ## BUG bash stdout-json: ""
134
135 # These shells don't understand @P
136
137 ## N-I dash/ash stdout-json: ""
138 ## N-I dash/ash status: 2
139
140 ## N-I zsh stdout-json: ""
141 ## N-I zsh status: 1
142
143
144 #### 'echo' and printf fail on writing to full disk
145
146 # Inspired by https://blog.sunfishcode.online/bugs-in-hello-world/
147
148 echo hi > /dev/full
149 echo status=$?
150
151 printf '%s\n' hi > /dev/full
152 echo status=$?
153
154 ## STDOUT:
155 status=1
156 status=1
157 ## END
158
159 #### other builtins fail on writing to full disk
160
161 type echo > /dev/full
162 echo status=$?
163
164 # other random builtin
165 ulimit -a > /dev/full
166 echo status=$?
167
168 ## STDOUT:
169 status=1
170 status=1
171 ## END
172
173 ## BUG mksh/zsh STDOUT:
174 status=0
175 status=0
176 ## END
177
178 #### subshell while running a script (regression)
179 # Ensures that spawning a subshell doesn't cause a seek on the file input stream
180 # representing the current script (issue #1233).
181 cat >tmp.sh <<'EOF'
182 echo start
183 (:)
184 echo end
185 EOF
186 $SH tmp.sh
187 ## STDOUT:
188 start
189 end
190 ## END
191
192 #### for loop (issue #1446)
193 case $SH in (dash|mksh|ash) exit ;; esac
194
195 for (( n=0; n<(3-(1)); n++ )) ; do echo $n; done
196
197 ## STDOUT:
198 0
199 1
200 ## END
201 ## N-I dash/mksh/ash STDOUT:
202 ## END
203
204
205
206 #### for loop 2 (issue #1446)
207 case $SH in (dash|mksh|ash) exit ;; esac
208
209
210 for (( n=0; n<(3- (1)); n++ )) ; do echo $n; done
211
212 ## STDOUT:
213 0
214 1
215 ## END
216 ## N-I dash/mksh/ash STDOUT:
217 ## END
218
219 #### autoconf word split (#1449)
220
221 mysed() {
222 for line in "$@"; do
223 echo "[$line]"
224 done
225 }
226
227 sedinputs="f1 f2"
228 sedscript='my sed command'
229
230 # Parsed and evaluated correctly: with word_part.EscapedLiteral \"
231
232 x=$(eval "mysed -n \"\$sedscript\" $sedinputs")
233 echo '--- $()'
234 echo "$x"
235
236 # With backticks, the \" gets lost somehow
237
238 x=`eval "mysed -n \"\$sedscript\" $sedinputs"`
239 echo '--- backticks'
240 echo "$x"
241
242
243 # Test it in a case statement
244
245 case `eval "mysed -n \"\$sedscript\" $sedinputs"` in
246 (*'[my sed command]'*)
247 echo 'NOT SPLIT'
248 ;;
249 esac
250
251 ## STDOUT:
252 --- $()
253 [-n]
254 [my sed command]
255 [f1]
256 [f2]
257 --- backticks
258 [-n]
259 [my sed command]
260 [f1]
261 [f2]
262 NOT SPLIT
263 ## END
264
265 #### autoconf arithmetic - relaxed eval_unsafe_arith (#1450)
266
267 as_fn_arith ()
268 {
269 as_val=$(( $* ))
270 }
271 as_fn_arith 1 + 1
272 echo $as_val
273
274 ## STDOUT:
275 2
276 ## END
277
278 #### command execution $(echo 42 | tee PWNED) not allowed
279
280 rm -f PWNED
281
282 x='a[$(echo 42 | tee PWNED)]=1'
283 echo $(( x ))
284
285 if test -f PWNED; then
286 cat PWNED
287 else
288 echo NOPE
289 fi
290
291 ## status: 1
292 ## OK dash/ash status: 2
293 ## stdout-json: ""
294 ## BUG bash/mksh/zsh status: 0
295 ## BUG bash/mksh/zsh STDOUT:
296 1
297 42
298 ## END
299
300 #### process sub <(echo 42 | tee PWNED) not allowed
301
302 rm -f PWNED
303
304 x='a[<(echo 42 | tee PWNED)]=1'
305 echo $(( x ))
306
307 if test -f PWNED; then
308 cat PWNED
309 else
310 echo NOPE
311 fi
312
313 ## status: 1
314 ## stdout-json: ""
315
316 ## OK dash/ash status: 2
317
318 # bash keeps going
319 ## BUG bash status: 0
320 ## BUG bash STDOUT:
321 NOPE
322 ## END
323
324
325 #### unset doesn't allow command execution
326
327 typeset -a a # for mksh
328 a=(42)
329 echo len=${#a[@]}
330
331 unset -v 'a[$(echo 0 | tee PWNED)]'
332 echo len=${#a[@]}
333
334 if test -f PWNED; then
335 echo PWNED
336 cat PWNED
337 else
338 echo NOPE
339 fi
340
341 ## status: 1
342 ## STDOUT:
343 len=1
344 ## END
345
346 ## N-I dash/ash status: 2
347 ## N-I dash/ash stdout-json: ""
348
349 ## BUG bash/mksh status: 0
350 ## BUG bash/mksh STDOUT:
351 len=1
352 len=0
353 PWNED
354 0
355 ## END
356
357 ## BUG zsh status: 0
358 ## BUG zsh STDOUT:
359 len=1
360 len=1
361 PWNED
362 0
363 ## END
364
365 #### printf integer size bug
366
367 # from Koiche on Zulip
368
369 printf '%x\n' 2147483648
370 printf '%u\n' 2147483648
371 ## STDOUT:
372 80000000
373 2147483648
374 ## END
375
376 #### (( status bug
377
378 # from Koiche on Zulip
379
380 case $SH in dash|ash) exit ;; esac
381
382 (( 1 << 32 ))
383 echo status=$?
384
385 (( 1 << 32 )) && echo yes
386
387 ## STDOUT:
388 status=0
389 yes
390 ## END
391
392 ## N-I dash/ash STDOUT:
393 ## END
394
395 #### autotools as_fn_arith bug in configure
396
397 # Causes 'grep -e' check to infinite loop.
398 # Reduced from a configure script.
399
400 as_fn_arith() {
401 as_val=$(( $* ))
402 }
403
404 as_fn_arith 0 + 1
405 echo as_val=$as_val
406 ## STDOUT:
407 as_val=1
408 ## END
409
410 #### osh-native duplicates stdin - is this a test harness issue?
411
412 echo $0 | grep -o sh
413
414 ## STDOUT:
415 sh
416 ## END
417
418 #### bug from pnut: negative number $((-1))
419
420 # https://lobste.rs/s/lplim1/design_self_compiling_c_transpiler#c_km2ywc
421
422 [ $((-42)) -le 0 ]
423 echo status=$?
424
425 [ $((-1)) -le 0 ]
426 echo status=$?
427
428 echo
429
430 [ -1 -le 0 ]
431 echo status=$?
432
433 [ -42 -le 0 ]
434 echo status=$?
435
436 echo
437
438 test -1 -le 0
439 echo status=$?
440
441 test -42 -le 0
442 echo status=$?
443
444 ## STDOUT:
445 status=0
446 status=0
447
448 status=0
449 status=0
450
451 status=0
452 status=0
453 ## END
454
455 #### negative octal numbers, etc.
456
457 # zero
458 [ -0 -eq 0 ]
459 echo zero=$?
460
461 # octal numbers can be negative
462 [ -0123 -eq -83 ]
463 echo octal=$?
464
465 # hex doesn't have negative numbers?
466 [ -0xff -eq -255 ]
467 echo hex=$?
468
469 # base N doesn't either
470 [ -64#a -eq -10 ]
471 echo baseN=$?
472
473 ## STDOUT:
474 zero=0
475 octal=1
476 hex=2
477 baseN=2
478 ## END
479
480 #### More negative numbers
481 case $SH in dash) exit ;; esac
482
483 [[ -1 -le 0 ]]
484 echo status=$?
485
486 [[ $((-1)) -le 0 ]]
487 echo status=$?
488
489 ## STDOUT:
490 status=0
491 status=0
492 ## END
493
494 ## N-I dash STDOUT:
495 ## END
496