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 for exec is a special case (versus e.g. readonly)
81
82 pre1=pre1 readonly x=x
83 pre2=pre2 exec sh -c 'echo pre1=$pre1 x=$x pre2=$pre2'
84
85 ## STDOUT:
86 pre1= x= pre2=pre2
87 ## END
88 ## BUG yash STDOUT:
89 pre1=pre1 x= pre2=pre2
90 ## END
91
92 #### exec without args is a special case of the special case in some shells
93
94 FOO=bar exec >& 2
95 echo FOO=$FOO
96 #declare -p | grep FOO
97
98 ## STDERR:
99 FOO=
100 ## END
101
102 ## OK dash/mksh/ash/yash STDERR:
103 FOO=bar
104 ## END
105
106 #### Which shells allow special builtins to be redefined?
107 eval() {
108 echo 'eval func' "$@"
109 }
110 eval 'echo hi'
111
112 # we allow redefinition, but the definition is NOT used!
113 ## status: 0
114 ## STDOUT:
115 hi
116 ## END
117
118 # we PREVENT redefinition
119 ## OK dash/ash status: 2
120 ## OK dash/ash STDOUT:
121 ## END
122
123 # should not allow redefinition
124 ## BUG bash/zsh status: 0
125 ## BUG bash/zsh STDOUT:
126 eval func echo hi
127 ## END
128
129
130 #### Special builtins can't be redefined as shell functions (set -o posix)
131 case $SH in
132 bash) set -o posix ;;
133 esac
134
135 eval 'echo hi'
136
137 eval() {
138 echo 'sh func' "$@"
139 }
140
141 eval 'echo hi'
142
143 ## status: 0
144 ## STDOUT:
145 hi
146 hi
147 ## END
148
149 ## OK bash/dash/ash status: 2
150 ## OK bash/dash/ash STDOUT:
151 hi
152 ## END
153
154 ## BUG zsh status: 0
155 ## BUG zsh STDOUT:
156 hi
157 sh func echo hi
158 ## END
159
160 #### Non-special builtins CAN be redefined as functions
161 test -n "$BASH_VERSION" && set -o posix
162 true() {
163 echo 'true func'
164 }
165 true hi
166 echo status=$?
167 ## STDOUT:
168 true func
169 status=0
170 ## END
171
172 #### Shift is special and fails whole script
173
174 # https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_14
175 #
176 # 2.8.1 - Consequences of shell errors
177 #
178 # Special built-ins should exit a non-interactive shell
179 # bash and busybox dont't implement this even with set -o posix, so it seems risky
180 # dash and mksh do it; so does AT&T ksh
181
182 $SH -c '
183 if test -n "$BASH_VERSION"; then
184 set -o posix
185 fi
186 set -- a b
187 shift 3
188 echo status=$?
189 '
190 if test "$?" != 0; then
191 echo 'non-zero status'
192 fi
193
194 ## STDOUT:
195 non-zero status
196 ## END
197
198 ## N-I bash/zsh/ash/yash/osh status: 0
199 ## N-I bash/zsh/ash/yash/osh STDOUT:
200 status=1
201 ## END
202
203 #### set is special and fails whole script, even if using || true
204 $SH -c '
205 if test -n "$BASH_VERSION"; then
206 set -o posix
207 fi
208
209 shopt -s invalid_ || true
210 echo ok
211 set -o invalid_ || true
212 echo should not get here
213 '
214 if test "$?" != 0; then
215 echo 'non-zero status'
216 fi
217
218 ## STDOUT:
219 ok
220 non-zero status
221 ## END
222
223 ## N-I bash/ash/yash/osh status: 0
224 ## N-I bash/ash/yash/osh STDOUT:
225 ok
226 should not get here
227 ## END
228
229 #### bash 'type' gets confused - says 'function', but runs builtin
230 case $SH in dash|mksh|zsh|ash|yash) exit ;; esac
231
232 echo TRUE
233 type -t true # builtin
234 true() { echo true func; }
235 type -t true # now a function
236 echo ---
237
238 echo EVAL
239
240 type -t eval # builtin
241 # define function before set -o posix
242 eval() { echo "shell function: $1"; }
243 # bash runs the FUNCTION, but OSH finds the special builtin
244 # OSH doesn't need set -o posix
245 eval 'echo before posix'
246
247 if test -n "$BASH_VERSION"; then
248 # this makes the eval definition invisible!
249 set -o posix
250 fi
251
252 eval 'echo after posix' # this is the builtin eval
253 # bash claims it's a function, but it's a builtin
254 type -t eval
255
256 # it finds the function and the special builtin
257 #type -a eval
258
259 ## BUG bash STDOUT:
260 TRUE
261 builtin
262 function
263 ---
264 EVAL
265 builtin
266 shell function: echo before posix
267 after posix
268 function
269 ## END
270
271 ## STDOUT:
272 TRUE
273 builtin
274 function
275 ---
276 EVAL
277 builtin
278 before posix
279 after posix
280 builtin
281 ## END
282
283 ## N-I dash/mksh/zsh/ash/yash STDOUT:
284 ## END
285
286 #### command, builtin - both can be redefined, not special (regression)
287 case $SH in dash|ash|yash) exit ;; esac
288
289 builtin echo b
290 command echo c
291
292 builtin() {
293 echo builtin-redef "$@"
294 }
295
296 command() {
297 echo command-redef "$@"
298 }
299
300 builtin echo b
301 command echo c
302
303 ## STDOUT:
304 b
305 c
306 builtin-redef echo b
307 command-redef echo c
308 ## END
309 ## N-I dash/ash/yash STDOUT:
310 ## END