1 ## compare_shells: dash bash-4.4 mksh
2
3 # In this file:
4 #
5 # - strict_control-flow: break/continue at the top level should be fatal!
6 #
7 # Other tests:
8 # - spec/errexit-strict: command subs inherit errexit
9 # - TODO: does bash 4.4. use inherit_errexit?
10 #
11 # - spec/var-op-other tests strict_word-eval (negative indices and invalid
12 # utf-8)
13 # - hm I think these should be the default? compat-word-eval?
14 #
15 # - spec/arith tests strict_arith - invalid strings become 0
16 # - OSH has a warning that can turn into an error. I think the error could
17 # be the default (since this was a side effect of "ShellMathShock")
18
19 # - strict_array: unimplemented.
20 # - WAS undef[2]=x, but bash-completion relied on the associative array
21 # version of that.
22 # - TODO: It should disable decay_array EVERYWHERE except a specific case like:
23 # - s="${a[*]}" # quoted, the unquoted ones glob in a command context
24 # - spec/dbracket has array comparison relevant to the case below
25 #
26 # Most of those options could be compat-*.
27 #
28 # One that can't: strict_scope disables dynamic scope.
29
30
31 #### strict_arith option
32 shopt -s strict_arith
33 ## status: 0
34 ## N-I bash status: 1
35 ## N-I dash/mksh status: 127
36
37 #### Sourcing a script that returns at the top level
38 echo one
39 . $REPO_ROOT/spec/testdata/return-helper.sh
40 echo $?
41 echo two
42 ## STDOUT:
43 one
44 return-helper.sh
45 42
46 two
47 ## END
48
49 #### top level control flow
50 $SH $REPO_ROOT/spec/testdata/top-level-control-flow.sh
51 ## status: 0
52 ## STDOUT:
53 SUBSHELL
54 BREAK
55 CONTINUE
56 RETURN
57 ## OK bash STDOUT:
58 SUBSHELL
59 BREAK
60 CONTINUE
61 RETURN
62 DONE
63 ## END
64
65 #### errexit and top-level control flow
66 $SH -o errexit $REPO_ROOT/spec/testdata/top-level-control-flow.sh
67 ## status: 2
68 ## OK bash status: 1
69 ## STDOUT:
70 SUBSHELL
71 ## END
72
73 #### shopt -s strict_control_flow
74 shopt -s strict_control_flow || true
75 echo break
76 break
77 echo hi
78 ## STDOUT:
79 break
80 ## END
81 ## status: 1
82 ## N-I dash/bash/mksh STDOUT:
83 break
84 hi
85 # END
86 ## N-I dash/bash/mksh status: 0
87
88 #### return at top level is an error
89 return
90 echo "status=$?"
91 ## stdout-json: ""
92 ## OK bash STDOUT:
93 status=1
94 ## END
95
96 #### continue at top level is NOT an error
97 # NOTE: bash and mksh both print warnings, but don't exit with an error.
98 continue
99 echo status=$?
100 ## stdout: status=0
101
102 #### break at top level is NOT an error
103 break
104 echo status=$?
105 ## stdout: status=0
106
107 #### empty argv WITHOUT strict_argv
108 x=''
109 $x
110 echo status=$?
111
112 if $x; then
113 echo VarSub
114 fi
115
116 if $(echo foo >/dev/null); then
117 echo CommandSub
118 fi
119
120 if "$x"; then
121 echo VarSub
122 else
123 echo VarSub FAILED
124 fi
125
126 if "$(echo foo >/dev/null)"; then
127 echo CommandSub
128 else
129 echo CommandSub FAILED
130 fi
131
132 ## STDOUT:
133 status=0
134 VarSub
135 CommandSub
136 VarSub FAILED
137 CommandSub FAILED
138 ## END
139
140 #### empty argv WITH strict_argv
141 shopt -s strict_argv || true
142 echo empty
143 x=''
144 $x
145 echo status=$?
146 ## status: 1
147 ## STDOUT:
148 empty
149 ## END
150 ## N-I dash/bash/mksh status: 0
151 ## N-I dash/bash/mksh STDOUT:
152 empty
153 status=0
154 ## END
155
156 #### Arrays are incorrectly compared, but strict_array prevents it
157
158 # NOTE: from spec/dbracket has a test case like this
159 # sane-array should turn this ON.
160 # bash and mksh allow this because of decay
161
162 a=('a b' 'c d')
163 b=('a' 'b' 'c' 'd')
164 echo ${#a[@]}
165 echo ${#b[@]}
166 [[ "${a[@]}" == "${b[@]}" ]] && echo EQUAL
167
168 shopt -s strict_array || true
169 [[ "${a[@]}" == "${b[@]}" ]] && echo EQUAL
170
171 ## status: 1
172 ## STDOUT:
173 2
174 4
175 EQUAL
176 ## END
177 ## OK bash/mksh status: 0
178 ## OK bash/mksh STDOUT:
179 2
180 4
181 EQUAL
182 EQUAL
183 ## END
184 ## N-I dash status: 2
185 ## N-I dash stdout-json: ""
186
187 #### automatically creating arrays WITHOUT strict_array
188 undef[2]=x
189 undef[3]=y
190 argv.py "${undef[@]}"
191 ## STDOUT:
192 ['x', 'y']
193 ## END
194 ## N-I dash status: 2
195 ## N-I dash stdout-json: ""
196
197 #### automatically creating arrays are INDEXED, not associative
198 shopt -u strict_arith || true
199
200 undef[2]=x
201 undef[3]=y
202 x='bad'
203 # bad gets coerced to zero, but this is part of the RECURSIVE arithmetic
204 # behavior, which we want to disallow. Consider disallowing in OSH.
205
206 undef[$x]=zzz
207 argv.py "${undef[@]}"
208 ## STDOUT:
209 ['zzz', 'x', 'y']
210 ## END
211 ## N-I dash status: 2
212 ## N-I dash stdout-json: ""
213
214 #### simple_eval_builtin
215 for i in 1 2; do
216 eval # zero args
217 echo status=$?
218 eval echo one
219 echo status=$?
220 eval 'echo two'
221 echo status=$?
222 shopt -s simple_eval_builtin
223 echo ---
224 done
225 ## STDOUT:
226 status=0
227 one
228 status=0
229 two
230 status=0
231 ---
232 status=2
233 status=2
234 two
235 status=0
236 ---
237 ## END
238 ## N-I dash/bash/mksh STDOUT:
239 status=0
240 one
241 status=0
242 two
243 status=0
244 ---
245 status=0
246 one
247 status=0
248 two
249 status=0
250 ---
251 ## END
252
253
254 #### strict_parse_slice means you need explicit length
255 case $SH in bash*|dash|mksh) exit ;; esac
256
257 $SH -c '
258 a=(1 2 3); echo /${a[@]::}/
259 '
260 echo status=$?
261
262 $SH -c '
263 shopt --set strict_parse_slice
264
265 a=(1 2 3); echo /${a[@]::}/
266 '
267 echo status=$?
268
269 ## STDOUT:
270 //
271 status=0
272 status=2
273 ## END
274
275 ## N-I bash/dash/mksh STDOUT:
276 ## END
277
278
279 #### Control flow must be static in YSH (strict_control_flow)
280 case $SH in bash*|dash|mksh) exit ;; esac
281
282 shopt --set ysh:all
283
284 for x in a b c {
285 echo $x
286 if (x === 'a') {
287 break
288 }
289 }
290
291 echo ---
292
293 for keyword in break continue return exit {
294 try {
295 $[ENV.SH] -o ysh:all -c '
296 var k = $1
297 for x in a b c {
298 echo $x
299 if (x === "a") {
300 $k
301 }
302 }
303 ' unused $keyword
304 }
305 echo code=$[_error.code]
306 echo '==='
307 }
308
309 ## STDOUT:
310 a
311 ---
312 a
313 code=1
314 ===
315 a
316 code=1
317 ===
318 a
319 code=1
320 ===
321 a
322 code=1
323 ===
324 ## END
325
326 ## N-I bash/dash/mksh STDOUT:
327 ## END
328
329 #### shopt -s strict_binding: Persistent prefix bindings not allowed on special builtins
330
331 shopt --set strict:all
332
333 # This differs from what it means in a process
334 FOO=bar eval 'echo FOO=$FOO'
335 echo FOO=$FOO
336
337 ## status: 1
338 ## STDOUT:
339 ## END
340
341 ## BUG bash status: 0
342 ## BUG bash STDOUT:
343 FOO=bar
344 FOO=
345 ## END
346
347 ## N-I dash/mksh status: 0
348 ## N-I dash/mksh STDOUT:
349 FOO=bar
350 FOO=bar
351 ## END