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