1 ## oils_failures_allowed: 5
2 ## compare_shells: bash mksh ash
3
4 # Notes on bash semantics:
5 #
6 # https://www.gnu.org/software/bash/manual/bash.html
7 #
8 # The trap builtin (see Bourne Shell Builtins) allows an ERR pseudo-signal
9 # specification, similar to EXIT and DEBUG. Commands specified with an ERR trap
10 # are executed after a simple command fails, with a few exceptions. The ERR
11 # trap is not inherited by shell functions unless the -o errtrace option to the
12 # set builtin is enabled.
13
14
15 #### trap can use original $LINENO
16
17 trap 'echo line=$LINENO' ERR
18
19 false
20 false
21 echo ok
22
23 ## STDOUT:
24 line=3
25 line=4
26 ok
27 ## END
28
29 #### trap ERR and if statement
30
31 if test -f /nope; then echo file exists; fi
32
33 trap 'echo err' ERR
34 #trap 'echo line=$LINENO' ERR
35
36 if test -f /nope; then echo file exists; fi
37
38 ## STDOUT:
39 ## END
40
41 #### trap ERR does not run in errexit situations
42
43 trap 'echo line=$LINENO' ERR
44
45 if false; then
46 echo if
47 fi
48
49 while false; do
50 echo while
51 done
52
53 until false; do
54 echo until
55 break
56 done
57
58 false || false || false
59
60 false && false && false
61
62 false; false; false
63
64 echo ok
65
66 ## STDOUT:
67 until
68 line=16
69 line=20
70 line=20
71 line=20
72 ok
73 ## END
74
75 #### trap ERR pipeline (also errexit)
76
77 # mksh and bash have different line numbers in this case
78 trap 'echo err' ERR
79 #trap 'echo line=$LINENO' ERR
80
81 # it's run for the last 'false'
82 false | false | false
83
84 # it's never run here
85 ! true
86 ! false
87
88 ## STDOUT:
89 err
90 ## END
91
92 #### trap ERR not active in shell functions in (bash behavior)
93
94 trap 'echo line=$LINENO' ERR
95
96 f() {
97 false
98 true
99 }
100
101 f
102
103 ## STDOUT:
104 ## END
105
106 ## N-I mksh STDOUT:
107 line=4
108 ## END
109
110 #### trap ERR shell function - with errtrace
111
112 trap 'echo line=$LINENO' ERR
113
114 passing() {
115 false # line 4
116 true
117 }
118
119 failing() {
120 true
121 false
122 }
123
124 passing
125 failing
126
127 set -o errtrace
128
129 echo 'now with errtrace'
130 passing
131 failing
132
133 echo ok
134
135 ## STDOUT:
136 line=14
137 now with errtrace
138 line=4
139 line=10
140 line=20
141 ok
142 ## END
143
144 ## BUG mksh status: 1
145 ## BUG mksh STDOUT:
146 line=4
147 line=10
148 ## END
149
150
151 #### trap ERR with YSH proc
152
153 case $SH in bash|mksh|ash) exit ;; esac
154
155 # seems the same
156
157 shopt -s ysh:upgrade
158
159 proc abc { echo abc }
160 if test -f /nope { echo file exists }
161 trap abc ERR
162 if test -f /nope { echo file exists }
163
164 ## STDOUT:
165 abc
166 ## END
167
168 ## N-I bash/mksh/ash STDOUT:
169 ## END
170
171 #### trap ERR
172 err() {
173 echo "err [$@] $?"
174 }
175 trap 'err x y' ERR
176
177 echo A
178
179 false
180 echo B
181
182 ( exit 42 )
183 echo C
184
185 trap - ERR # disable trap
186
187 false
188 echo D
189
190 trap 'echo after errexit $?' ERR
191
192 set -o errexit
193
194 ( exit 99 )
195 echo E
196
197 ## status: 99
198 ## STDOUT:
199 A
200 err [x y] 1
201 B
202 err [x y] 42
203 C
204 D
205 after errexit 99
206 ## END
207 ## N-I dash STDOUT:
208 A
209 B
210 C
211 D
212 ## END
213
214 #### trap ERR and pipelines (lastpipe and PIPESTATUS difference)
215 case $SH in ash) exit ;; esac
216
217 err() {
218 echo "err [$@] status=$? [${PIPESTATUS[@]}]"
219 }
220 trap 'err' ERR
221
222 echo A
223
224 false
225
226 # succeeds
227 echo B | grep B
228
229 # fails
230 echo C | grep zzz
231
232 echo D | grep zzz | cat
233
234 set -o pipefail
235 echo E | grep zzz | cat
236
237 trap - ERR # disable trap
238
239 echo F | grep zz
240 echo ok
241
242 ## STDOUT:
243 A
244 err [] status=1 [1]
245 B
246 err [] status=1 [0 1]
247 err [] status=1 [0 1 0]
248 ok
249 ## END
250
251 # lastpipe semantics mean we get another call!
252 # also we don't set PIPESTATUS unless we get a pipeline
253
254 ## OK osh STDOUT:
255 A
256 err [] status=1 []
257 B
258 err [] status=1 [0 0]
259 err [] status=1 [0 1]
260 err [] status=1 [0 1 0]
261 ok
262 ## END
263
264 ## N-I ash STDOUT:
265 ## END
266
267 #### error in trap ERR (recursive)
268 case $SH in dash) exit ;; esac
269
270 err() {
271 echo err status $?
272 ( exit 2 )
273 }
274 trap 'err' ERR
275
276 echo A
277 false
278 echo B
279
280 ## STDOUT:
281 A
282 err status 1
283 B
284 ## END
285 ## N-I dash STDOUT:
286 ## END
287