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 status: 1
102 # Note: zsh should return 1 or 2
103 ## BUG zsh status: 0
104 ## STDOUT:
105 ## END
106
107
108 #### file with NUL byte
109 echo -e 'echo one \0 echo two' > tmp.sh
110 $SH tmp.sh
111 ## STDOUT:
112 one echo two
113 ## END
114 ## OK osh STDOUT:
115 one
116 ## END
117 ## N-I dash stdout-json: ""
118 ## N-I dash status: 127
119 ## OK bash stdout-json: ""
120 ## OK bash status: 126
121 ## OK zsh stdout-json: "one \u0000echo two\n"
122
123 #### fastlex: PS1 format string that's incomplete / with NUL byte
124 case $SH in bash) exit ;; esac
125
126 x=$'\\D{%H:%M' # leave off trailing }
127 echo x=${x@P}
128
129 ## STDOUT:
130 x=\D{%H:%M
131 ## END
132
133 # bash just ignores the missing }
134 ## BUG bash stdout-json: ""
135
136 # These shells don't understand @P
137
138 ## N-I dash/ash stdout-json: ""
139 ## N-I dash/ash status: 2
140
141 ## N-I zsh stdout-json: ""
142 ## N-I zsh status: 1
143
144
145 #### 'echo' and printf fail on writing to full disk
146
147 # Inspired by https://blog.sunfishcode.online/bugs-in-hello-world/
148
149 echo hi > /dev/full
150 echo status=$?
151
152 printf '%s\n' hi > /dev/full
153 echo status=$?
154
155 ## STDOUT:
156 status=1
157 status=1
158 ## END
159
160 #### other builtins fail on writing to full disk
161
162 type echo > /dev/full
163 echo status=$?
164
165 # other random builtin
166 ulimit -a > /dev/full
167 echo status=$?
168
169 ## STDOUT:
170 status=1
171 status=1
172 ## END
173
174 ## BUG mksh/zsh STDOUT:
175 status=0
176 status=0
177 ## END
178
179 #### subshell while running a script (regression)
180 # Ensures that spawning a subshell doesn't cause a seek on the file input stream
181 # representing the current script (issue #1233).
182 cat >tmp.sh <<'EOF'
183 echo start
184 (:)
185 echo end
186 EOF
187 $SH tmp.sh
188 ## STDOUT:
189 start
190 end
191 ## END
192
193 #### for loop (issue #1446)
194 case $SH in (dash|mksh|ash) exit ;; esac
195
196 for (( n=0; n<(3-(1)); n++ )) ; do echo $n; done
197
198 ## STDOUT:
199 0
200 1
201 ## END
202 ## N-I dash/mksh/ash STDOUT:
203 ## END
204
205
206
207 #### for loop 2 (issue #1446)
208 case $SH in (dash|mksh|ash) exit ;; esac
209
210
211 for (( n=0; n<(3- (1)); n++ )) ; do echo $n; done
212
213 ## STDOUT:
214 0
215 1
216 ## END
217 ## N-I dash/mksh/ash STDOUT:
218 ## END
219
220 #### autoconf word split (#1449)
221
222 mysed() {
223 for line in "$@"; do
224 echo "[$line]"
225 done
226 }
227
228 sedinputs="f1 f2"
229 sedscript='my sed command'
230
231 # Parsed and evaluated correctly: with word_part.EscapedLiteral \"
232
233 x=$(eval "mysed -n \"\$sedscript\" $sedinputs")
234 echo '--- $()'
235 echo "$x"
236
237 # With backticks, the \" gets lost somehow
238
239 x=`eval "mysed -n \"\$sedscript\" $sedinputs"`
240 echo '--- backticks'
241 echo "$x"
242
243
244 # Test it in a case statement
245
246 case `eval "mysed -n \"\$sedscript\" $sedinputs"` in
247 (*'[my sed command]'*)
248 echo 'NOT SPLIT'
249 ;;
250 esac
251
252 ## STDOUT:
253 --- $()
254 [-n]
255 [my sed command]
256 [f1]
257 [f2]
258 --- backticks
259 [-n]
260 [my sed command]
261 [f1]
262 [f2]
263 NOT SPLIT
264 ## END
265
266 #### autoconf arithmetic - relaxed eval_unsafe_arith (#1450)
267
268 as_fn_arith ()
269 {
270 as_val=$(( $* ))
271 }
272 as_fn_arith 1 + 1
273 echo $as_val
274
275 ## STDOUT:
276 2
277 ## END
278
279 #### command execution $(echo 42 | tee PWNED) not allowed
280
281 rm -f PWNED
282
283 x='a[$(echo 42 | tee PWNED)]=1'
284 echo $(( x ))
285
286 if test -f PWNED; then
287 cat PWNED
288 else
289 echo NOPE
290 fi
291
292 ## status: 1
293 ## OK dash/ash status: 2
294 ## stdout-json: ""
295 ## BUG bash/mksh/zsh status: 0
296 ## BUG bash/mksh/zsh STDOUT:
297 1
298 42
299 ## END
300
301 #### process sub <(echo 42 | tee PWNED) not allowed
302
303 rm -f PWNED
304
305 x='a[<(echo 42 | tee PWNED)]=1'
306 echo $(( x ))
307
308 if test -f PWNED; then
309 cat PWNED
310 else
311 echo NOPE
312 fi
313
314 ## status: 1
315 ## stdout-json: ""
316
317 ## OK dash/ash status: 2
318
319 # bash keeps going
320 ## BUG bash status: 0
321 ## BUG bash STDOUT:
322 NOPE
323 ## END
324
325
326 #### unset doesn't allow command execution
327
328 typeset -a a # for mksh
329 a=(42)
330 echo len=${#a[@]}
331
332 unset -v 'a[$(echo 0 | tee PWNED)]'
333 echo len=${#a[@]}
334
335 if test -f PWNED; then
336 echo PWNED
337 cat PWNED
338 else
339 echo NOPE
340 fi
341
342 ## status: 1
343 ## STDOUT:
344 len=1
345 ## END
346
347 ## N-I dash/ash status: 2
348 ## N-I dash/ash stdout-json: ""
349
350 ## BUG bash/mksh status: 0
351 ## BUG bash/mksh STDOUT:
352 len=1
353 len=0
354 PWNED
355 0
356 ## END
357
358 ## BUG zsh status: 0
359 ## BUG zsh STDOUT:
360 len=1
361 len=1
362 PWNED
363 0
364 ## END
365
366 #### printf integer size bug
367
368 # from Koiche on Zulip
369
370 printf '%x\n' 2147483648
371 printf '%u\n' 2147483648
372 ## STDOUT:
373 80000000
374 2147483648
375 ## END
376
377 #### (( status bug
378
379 # from Koiche on Zulip
380
381 case $SH in dash|ash) exit ;; esac
382
383 (( 1 << 32 ))
384 echo status=$?
385
386 (( 1 << 32 )) && echo yes
387
388 ## STDOUT:
389 status=0
390 yes
391 ## END
392
393 ## N-I dash/ash STDOUT:
394 ## END
395
396 #### autotools as_fn_arith bug in configure
397
398 # Causes 'grep -e' check to infinite loop.
399 # Reduced from a configure script.
400
401 as_fn_arith() {
402 as_val=$(( $* ))
403 }
404
405 as_fn_arith 0 + 1
406 echo as_val=$as_val
407 ## STDOUT:
408 as_val=1
409 ## END
410
411 #### osh-native duplicates stdin - is this a test harness issue?
412
413 echo $0 | grep -o sh
414
415 ## STDOUT:
416 sh
417 ## END
418