1 ## compare_shells: dash bash-4.4 mksh zsh
2 ## oils_failures_allowed: 0
3
4 #### Eval
5 eval "a=3"
6 echo $a
7 ## stdout: 3
8
9 #### eval accepts/ignores --
10 eval -- echo hi
11 ## STDOUT:
12 hi
13 ## END
14 ## BUG dash status: 127
15 ## BUG dash stdout-json: ""
16
17 #### eval usage
18 eval -
19 echo $?
20 eval -z
21 echo $?
22 ## STDOUT:
23 127
24 2
25 ## END
26 ## OK dash STDOUT:
27 127
28 127
29 ## END
30 ## OK mksh status: 1
31 ## OK mksh STDOUT:
32 127
33 ## END
34 ## OK zsh STDOUT:
35 0
36 127
37 ## END
38
39 #### eval string with 'break continue return error'
40
41 set -e
42
43 sh_func_that_evals() {
44 local code_str=$1
45 for i in 1 2; do
46 echo $i
47 eval "$code_str"
48 done
49 echo 'end func'
50 }
51
52 for code_str in break continue return false; do
53 echo "--- $code_str"
54 sh_func_that_evals "$code_str"
55 done
56 echo status=$?
57
58 ## status: 1
59 ## STDOUT:
60 --- break
61 1
62 end func
63 --- continue
64 1
65 2
66 end func
67 --- return
68 1
69 --- false
70 1
71 ## END
72
73 ## BUG mksh STDOUT:
74 --- break
75 1
76 2
77 end func
78 --- continue
79 1
80 2
81 end func
82 --- return
83 1
84 --- false
85 1
86 ## END
87
88 #### eval YSH block with 'break continue return error'
89 case $SH in dash|bash*|mksh|zsh) exit ;; esac
90
91 shopt -s ysh:all
92
93 proc proc_that_evals(; ; ;b) {
94 for i in 1 2; do
95 echo $i
96 call io->eval(b)
97 done
98 echo 'end func'
99 }
100
101 var cases = [
102 ['break', ^(break)],
103 ['continue', ^(continue)],
104 ['return', ^(return)],
105 ['false', ^(false)],
106 ]
107
108 for test_case in (cases) {
109 var code_str, block = test_case
110 echo "--- $code_str"
111 proc_that_evals (; ; block)
112 }
113 echo status=$?
114
115 ## status: 1
116 ## STDOUT:
117 --- break
118 1
119 end func
120 --- continue
121 1
122 2
123 end func
124 --- return
125 1
126 --- false
127 1
128 ## END
129
130 ## N-I dash/bash/mksh/zsh status: 0
131 ## N-I dash/bash/mksh/zsh STDOUT:
132 ## END
133
134 #### exit within eval (regression)
135 eval 'exit 42'
136 echo 'should not get here'
137 ## stdout-json: ""
138 ## status: 42
139
140 #### exit within source (regression)
141 cd $TMP
142 echo 'exit 42' > lib.sh
143 . ./lib.sh
144 echo 'should not get here'
145 ## stdout-json: ""
146 ## status: 42
147
148 #### Source
149 lib=$TMP/spec-test-lib.sh
150 echo 'LIBVAR=libvar' > $lib
151 . $lib # dash doesn't have source
152 echo $LIBVAR
153 ## stdout: libvar
154
155 #### source accepts/ignores --
156 echo 'echo foo' > $TMP/foo.sh
157 source -- $TMP/foo.sh
158 ## STDOUT:
159 foo
160 ## END
161 ## N-I dash stdout-json: ""
162 ## N-I dash status: 127
163
164 #### Source nonexistent
165 source /nonexistent/path
166 echo status=$?
167 ## stdout: status=1
168 ## OK dash/zsh stdout: status=127
169
170 #### Source with no arguments
171 source
172 echo status=$?
173 ## stdout: status=2
174 ## OK mksh/zsh stdout: status=1
175 ## N-I dash stdout: status=127
176
177 #### Source with arguments
178 . $REPO_ROOT/spec/testdata/show-argv.sh foo bar # dash doesn't have source
179 ## STDOUT:
180 show-argv: foo bar
181 ## END
182 ## N-I dash STDOUT:
183 show-argv:
184 ## END
185
186 #### Source from a function, mutating argv and defining a local var
187 f() {
188 . $REPO_ROOT/spec/testdata/source-argv.sh # no argv
189 . $REPO_ROOT/spec/testdata/source-argv.sh args to src # new argv
190 echo $@
191 echo foo=$foo # defined in source-argv.sh
192 }
193 f args to func
194 echo foo=$foo # not defined
195 ## STDOUT:
196 source-argv: args to func
197 source-argv: args to src
198 to func
199 foo=foo_val
200 foo=
201 ## END
202 ## N-I dash STDOUT:
203 source-argv: args to func
204 source-argv: to func
205 func
206 foo=foo_val
207 foo=
208 ## END
209
210 #### Source with syntax error
211 # TODO: We should probably use dash behavior of a fatal error.
212 # Although set-o errexit handles this. We don't want to break the invariant
213 # that a builtin like 'source' behaves like an external program. An external
214 # program can't halt the shell!
215 echo 'echo >' > $TMP/syntax-error.sh
216 . $TMP/syntax-error.sh
217 echo status=$?
218 ## stdout: status=2
219 ## OK bash/mksh stdout: status=1
220 ## OK zsh stdout: status=126
221 ## OK dash stdout-json: ""
222 ## OK dash status: 2
223
224 #### Eval with syntax error
225 eval 'echo >'
226 echo status=$?
227 ## stdout: status=2
228 ## OK bash/zsh stdout: status=1
229 ## OK dash stdout-json: ""
230 ## OK dash status: 2
231 ## OK mksh stdout-json: ""
232 ## OK mksh status: 1
233
234 #### Eval in does tilde expansion
235
236 x="~"
237 eval y="$x" # scalar
238 test "$x" = "$y" || echo FALSE
239 [[ $x == /* ]] || echo FALSE # doesn't start with /
240 [[ $y == /* ]] && echo TRUE
241
242 #argv "$x" "$y"
243
244 ## STDOUT:
245 FALSE
246 FALSE
247 TRUE
248 ## END
249 ## BUG dash status: 127
250 ## BUG dash stdout-json: "FALSE\n"
251 ## BUG mksh status: 1
252 ## BUG mksh stdout-json: "FALSE\n"
253
254 #### Eval in bash does tilde expansion in array
255
256 # the "make" plugin in bash-completion relies on this? wtf?
257 x="~"
258
259 # UPSTREAM CODE
260
261 #eval array=( "$x" )
262
263 # FIXED CODE -- proper quoting.
264
265 eval 'array=(' "$x" ')' # array
266
267 test "$x" = "${array[0]}" || echo FALSE
268 [[ $x == /* ]] || echo FALSE # doesn't start with /
269 [[ "${array[0]}" == /* ]] && echo TRUE
270 ## STDOUT:
271 FALSE
272 FALSE
273 TRUE
274 ## END
275 ## N-I dash status: 2
276 ## N-I dash stdout-json: ""
277 ## BUG mksh status: 1
278 ## BUG mksh STDOUT:
279 FALSE
280 ## END
281 ## BUG zsh status: 1
282 ## BUG zsh STDOUT:
283 FALSE
284 FALSE
285 ## END
286
287 #### source works for files in current directory (bash only)
288 cd $TMP
289 echo "echo current dir" > cmd
290 . cmd
291 echo status=$?
292 ## STDOUT:
293 current dir
294 status=0
295 ## END
296 ## N-I zsh STDOUT:
297 status=127
298 ## END
299
300 # This is a special builtin so failure is fatal.
301
302 ## N-I dash stdout-json: ""
303 ## N-I dash status: 2
304 ## N-I mksh stdout-json: ""
305 ## N-I mksh status: 1
306
307 #### source looks in PATH for files
308 mkdir -p dir
309 echo "echo hi" > dir/cmd
310 PATH="dir:$PATH"
311 . cmd
312 rm dir/cmd
313 ## STDOUT:
314 hi
315 ## END
316
317 #### source finds files in PATH before current dir
318 cd $TMP
319 mkdir -p dir
320 echo "echo path" > dir/cmd
321 echo "echo current dir" > cmd
322 PATH="dir:$PATH"
323 . cmd
324 echo status=$?
325 ## STDOUT:
326 path
327 status=0
328 ## END
329
330 #### source works for files in subdirectory
331 mkdir -p dir
332 echo "echo path" > dir/cmd
333 . dir/cmd
334 rm dir/cmd
335 ## STDOUT:
336 path
337 ## END
338
339 #### source doesn't crash when targeting a directory
340 cd $TMP
341 mkdir -p dir
342 . ./dir/
343 echo status=$?
344 ## stdout: status=1
345 ## OK dash/zsh/mksh stdout: status=0