OILS / spec / builtin-special.test.sh View on Github | oils.pub

310 lines, 137 significant
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
5foo=bar true
6echo foo=$foo
7
8true() {
9 echo true func
10}
11foo=bar true
12echo foo=$foo
13
14## STDOUT:
15foo=
16true func
17foo=
18## END
19
20## BUG mksh STDOUT:
21foo=
22true func
23foo=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)
31case $SH in
32 bash) set -o posix ;;
33esac
34
35foo=bar :
36echo foo=$foo
37
38# Not true when you use 'builtin'
39z=Z builtin :
40echo z=$Z
41
42## STDOUT:
43foo=bar
44z=
45## END
46
47## BUG zsh STDOUT:
48foo=
49z=
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
55case $SH in
56 bash) set -o posix ;;
57esac
58foo=bar readonly spam=eggs
59echo foo=$foo
60echo spam=$spam
61
62# should NOT be exported
63printenv.py foo
64printenv.py spam
65
66## STDOUT:
67foo=bar
68spam=eggs
69None
70None
71## END
72
73## BUG bash/yash STDOUT:
74foo=bar
75spam=eggs
76bar
77None
78## END
79
80#### Prefix binding for exec is a special case (versus e.g. readonly)
81
82pre1=pre1 readonly x=x
83pre2=pre2 exec sh -c 'echo pre1=$pre1 x=$x pre2=$pre2'
84
85## STDOUT:
86pre1= x= pre2=pre2
87## END
88## BUG yash STDOUT:
89pre1=pre1 x= pre2=pre2
90## END
91
92#### exec without args is a special case of the special case in some shells
93
94FOO=bar exec >& 2
95echo FOO=$FOO
96#declare -p | grep FOO
97
98## STDERR:
99FOO=
100## END
101
102## OK dash/mksh/ash/yash STDERR:
103FOO=bar
104## END
105
106#### Which shells allow special builtins to be redefined?
107eval() {
108 echo 'eval func' "$@"
109}
110eval 'echo hi'
111
112# we allow redefinition, but the definition is NOT used!
113## status: 0
114## STDOUT:
115hi
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:
126eval func echo hi
127## END
128
129
130#### Special builtins can't be redefined as shell functions (set -o posix)
131case $SH in
132 bash) set -o posix ;;
133esac
134
135eval 'echo hi'
136
137eval() {
138 echo 'sh func' "$@"
139}
140
141eval 'echo hi'
142
143## status: 0
144## STDOUT:
145hi
146hi
147## END
148
149## OK bash/dash/ash status: 2
150## OK bash/dash/ash STDOUT:
151hi
152## END
153
154## BUG zsh status: 0
155## BUG zsh STDOUT:
156hi
157sh func echo hi
158## END
159
160#### Non-special builtins CAN be redefined as functions
161test -n "$BASH_VERSION" && set -o posix
162true() {
163 echo 'true func'
164}
165true hi
166echo status=$?
167## STDOUT:
168true func
169status=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 '
183if test -n "$BASH_VERSION"; then
184 set -o posix
185fi
186set -- a b
187shift 3
188echo status=$?
189'
190if test "$?" != 0; then
191 echo 'non-zero status'
192fi
193
194## STDOUT:
195non-zero status
196## END
197
198## N-I bash/zsh/ash/yash/osh status: 0
199## N-I bash/zsh/ash/yash/osh STDOUT:
200status=1
201## END
202
203#### set is special and fails whole script, even if using || true
204$SH -c '
205if test -n "$BASH_VERSION"; then
206 set -o posix
207fi
208
209shopt -s invalid_ || true
210echo ok
211set -o invalid_ || true
212echo should not get here
213'
214if test "$?" != 0; then
215 echo 'non-zero status'
216fi
217
218## STDOUT:
219ok
220non-zero status
221## END
222
223## N-I bash/ash/yash/osh status: 0
224## N-I bash/ash/yash/osh STDOUT:
225ok
226should not get here
227## END
228
229#### bash 'type' gets confused - says 'function', but runs builtin
230case $SH in dash|mksh|zsh|ash|yash) exit ;; esac
231
232echo TRUE
233type -t true # builtin
234true() { echo true func; }
235type -t true # now a function
236echo ---
237
238echo EVAL
239
240type -t eval # builtin
241# define function before set -o posix
242eval() { echo "shell function: $1"; }
243# bash runs the FUNCTION, but OSH finds the special builtin
244# OSH doesn't need set -o posix
245eval 'echo before posix'
246
247if test -n "$BASH_VERSION"; then
248 # this makes the eval definition invisible!
249 set -o posix
250fi
251
252eval 'echo after posix' # this is the builtin eval
253# bash claims it's a function, but it's a builtin
254type -t eval
255
256# it finds the function and the special builtin
257#type -a eval
258
259## BUG bash STDOUT:
260TRUE
261builtin
262function
263---
264EVAL
265builtin
266shell function: echo before posix
267after posix
268function
269## END
270
271## STDOUT:
272TRUE
273builtin
274function
275---
276EVAL
277builtin
278before posix
279after posix
280builtin
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)
287case $SH in dash|ash|yash) exit ;; esac
288
289builtin echo b
290command echo c
291
292builtin() {
293 echo builtin-redef "$@"
294}
295
296command() {
297 echo command-redef "$@"
298}
299
300builtin echo b
301command echo c
302
303## STDOUT:
304b
305c
306builtin-redef echo b
307command-redef echo c
308## END
309## N-I dash/ash/yash STDOUT:
310## END