1 ## oils_failures_allowed: 0
2 ## compare_shells: bash dash mksh zsh ash yash
3
4 #### true is not special; prefix assignments don't persist, it can be redefined
5 foo=bar true
6 echo foo=$foo
7
8 true() {
9 echo true func
10 }
11 foo=bar true
12 echo foo=$foo
13
14 ## STDOUT:
15 foo=
16 true func
17 foo=
18 ## END
19
20 ## BUG mksh STDOUT:
21 foo=
22 true func
23 foo=bar
24 ## END
25
26 # POSIX rule about special builtins pointed at:
27 #
28 # https://www.reddit.com/r/oilshell/comments/5ykpi3/oildev_is_alive/
29
30 #### Prefix assignments persist after special builtins, like : (set -o posix)
31 case $SH in
32 bash) set -o posix ;;
33 esac
34
35 foo=bar :
36 echo foo=$foo
37
38 # Not true when you use 'builtin'
39 z=Z builtin :
40 echo z=$Z
41
42 ## STDOUT:
43 foo=bar
44 z=
45 ## END
46
47 ## BUG zsh STDOUT:
48 foo=
49 z=
50 ## END
51
52 #### Prefix assignments persist after readonly, but NOT exported (set -o posix)
53
54 # Bash only implements it behind the posix option
55 case $SH in
56 bash) set -o posix ;;
57 esac
58 foo=bar readonly spam=eggs
59 echo foo=$foo
60 echo spam=$spam
61
62 # should NOT be exported
63 printenv.py foo
64 printenv.py spam
65
66 ## STDOUT:
67 foo=bar
68 spam=eggs
69 None
70 None
71 ## END
72
73 ## BUG bash/yash STDOUT:
74 foo=bar
75 spam=eggs
76 bar
77 None
78 ## END
79
80 #### Prefix binding to exec - adapted from toysh
81 cat > snork << 'EOF'
82 #!/bin/sh
83 echo hello $BLAH
84 EOF
85 chmod +x snork
86
87 $SH -c 'BLAH=123; ./snork'
88 $SH -c 'BLAH=123 ./snork'
89 echo
90
91 $SH -c 'BLAH=123; exec ./snork'
92 $SH -c 'BLAH=123 exec ./snork'
93 echo
94
95 # WHY different?
96 $SH -c 'BLAH=123; readonly foo; exec ./snork'
97 $SH -c 'BLAH=123 readonly foo; ./snork'
98 echo
99
100 $SH -c 'BLAH=123; : foo; exec ./snork'
101 $SH -c 'BLAH=123 : foo; ./snork'
102
103 ## STDOUT:
104 hello
105 hello 123
106
107 hello
108 hello 123
109
110 hello
111 hello
112
113 hello
114 hello
115 ## END
116
117 ## BUG yash STDOUT:
118 hello
119 hello 123
120
121 hello
122 hello 123
123
124 hello
125 hello 123
126
127 hello
128 hello 123
129 ## END
130
131 #### Prefix binding for readonly vs. exec
132
133 pre1=pre1 readonly x=x
134 pre2=pre2 exec sh -c 'echo pre1=$pre1 x=$x pre2=$pre2'
135
136 ## STDOUT:
137 pre1= x= pre2=pre2
138 ## END
139 ## BUG yash STDOUT:
140 pre1=pre1 x= pre2=pre2
141 ## END
142
143 #### Which shells allow special builtins to be redefined?
144 eval() {
145 echo 'eval func' "$@"
146 }
147 eval 'echo hi'
148
149 # we allow redefinition, but the definition is NOT used!
150 ## status: 0
151 ## STDOUT:
152 hi
153 ## END
154
155 # we PREVENT redefinition
156 ## OK dash/ash status: 2
157 ## OK dash/ash STDOUT:
158 ## END
159
160 # should not allow redefinition
161 ## BUG bash/zsh status: 0
162 ## BUG bash/zsh STDOUT:
163 eval func echo hi
164 ## END
165
166
167 #### Special builtins can't be redefined as shell functions (set -o posix)
168 case $SH in
169 bash) set -o posix ;;
170 esac
171
172 eval 'echo hi'
173
174 eval() {
175 echo 'sh func' "$@"
176 }
177
178 eval 'echo hi'
179
180 ## status: 0
181 ## STDOUT:
182 hi
183 hi
184 ## END
185
186 ## OK bash/dash/ash status: 2
187 ## OK bash/dash/ash STDOUT:
188 hi
189 ## END
190
191 ## BUG zsh status: 0
192 ## BUG zsh STDOUT:
193 hi
194 sh func echo hi
195 ## END
196
197 #### Non-special builtins CAN be redefined as functions
198 test -n "$BASH_VERSION" && set -o posix
199 true() {
200 echo 'true func'
201 }
202 true hi
203 echo status=$?
204 ## STDOUT:
205 true func
206 status=0
207 ## END
208
209 #### Shift is special and fails whole script
210
211 # https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_14
212 #
213 # 2.8.1 - Consequences of shell errors
214 #
215 # Special built-ins should exit a non-interactive shell
216 # bash and busybox dont't implement this even with set -o posix, so it seems risky
217 # dash and mksh do it; so does AT&T ksh
218
219 $SH -c '
220 if test -n "$BASH_VERSION"; then
221 set -o posix
222 fi
223 set -- a b
224 shift 3
225 echo status=$?
226 '
227 if test "$?" != 0; then
228 echo 'non-zero status'
229 fi
230
231 ## STDOUT:
232 non-zero status
233 ## END
234
235 ## N-I bash/zsh/ash/yash/osh status: 0
236 ## N-I bash/zsh/ash/yash/osh STDOUT:
237 status=1
238 ## END
239
240 #### set is special and fails whole script, even if using || true
241 $SH -c '
242 if test -n "$BASH_VERSION"; then
243 set -o posix
244 fi
245
246 shopt -s invalid_ || true
247 echo ok
248 set -o invalid_ || true
249 echo should not get here
250 '
251 if test "$?" != 0; then
252 echo 'non-zero status'
253 fi
254
255 ## STDOUT:
256 ok
257 non-zero status
258 ## END
259
260 ## N-I bash/ash/yash/osh status: 0
261 ## N-I bash/ash/yash/osh STDOUT:
262 ok
263 should not get here
264 ## END
265
266 #### bash 'type' gets confused - says 'function', but runs builtin
267 case $SH in dash|mksh|zsh|ash|yash) exit ;; esac
268
269 echo TRUE
270 type -t true # builtin
271 true() { echo true func; }
272 type -t true # now a function
273 echo ---
274
275 echo EVAL
276
277 type -t eval # builtin
278 # define function before set -o posix
279 eval() { echo "shell function: $1"; }
280 # bash runs the FUNCTION, but OSH finds the special builtin
281 # OSH doesn't need set -o posix
282 eval 'echo before posix'
283
284 if test -n "$BASH_VERSION"; then
285 # this makes the eval definition invisible!
286 set -o posix
287 fi
288
289 eval 'echo after posix' # this is the builtin eval
290 # bash claims it's a function, but it's a builtin
291 type -t eval
292
293 # it finds the function and the special builtin
294 #type -a eval
295
296 ## BUG bash STDOUT:
297 TRUE
298 builtin
299 function
300 ---
301 EVAL
302 builtin
303 shell function: echo before posix
304 after posix
305 function
306 ## END
307
308 ## STDOUT:
309 TRUE
310 builtin
311 function
312 ---
313 EVAL
314 builtin
315 before posix
316 after posix
317 builtin
318 ## END
319
320 ## N-I dash/mksh/zsh/ash/yash STDOUT:
321 ## END
322
323 #### command, builtin - both can be redefined, not special (regression)
324 case $SH in dash|ash|yash) exit ;; esac
325
326 builtin echo b
327 command echo c
328
329 builtin() {
330 echo builtin-redef "$@"
331 }
332
333 command() {
334 echo command-redef "$@"
335 }
336
337 builtin echo b
338 command echo c
339
340 ## STDOUT:
341 b
342 c
343 builtin-redef echo b
344 command-redef echo c
345 ## END
346 ## N-I dash/ash/yash STDOUT:
347 ## END