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
|