1 # builtin-trap.test.sh
2
3 #### trap accepts/ignores --
4 trap -- 'echo hi' EXIT
5 echo done
6 ## STDOUT:
7 done
8 hi
9 ## END
10
11 #### trap 'echo hi' KILL (regression test, caught by smoosh suite)
12 trap 'echo hi' 9
13 echo status=$?
14 trap 'echo hi' KILL
15 echo status=$?
16 trap 'echo hi' STOP
17 echo status=$?
18 trap 'echo hi' TERM
19 echo status=$?
20 ## STDOUT:
21 status=0
22 status=0
23 status=0
24 status=0
25 ## END
26 ## OK osh STDOUT:
27 status=1
28 status=1
29 status=1
30 status=0
31 ## END
32
33 #### Register invalid trap
34 trap 'foo' SIGINVALID
35 ## status: 1
36
37 #### Remove invalid trap
38 trap - SIGINVALID
39 ## status: 1
40
41 #### SIGINT and INT are aliases
42 trap - SIGINT
43 echo $?
44 trap - INT
45 echo $?
46 ## STDOUT:
47 0
48 0
49 ## END
50 ## N-I dash STDOUT:
51 1
52 0
53 ## END
54
55 #### Invalid trap invocation
56 trap 'foo'
57 echo status=$?
58 ## stdout: status=2
59 ## OK dash stdout: status=1
60 ## BUG mksh stdout: status=0
61
62 #### exit 1 when trap code string is invalid
63 # All shells spew warnings to stderr, but don't actually exit! Bad!
64 trap 'echo <' EXIT
65 echo status=$?
66 ## stdout: status=1
67 ## BUG mksh status: 1
68 ## BUG mksh stdout: status=0
69 ## BUG dash/bash status: 0
70 ## BUG dash/bash stdout: status=0
71
72 #### trap EXIT calling exit
73 cleanup() {
74 echo "cleanup [$@]"
75 exit 42
76 }
77 trap 'cleanup x y z' EXIT
78 ## stdout: cleanup [x y z]
79 ## status: 42
80
81 #### trap EXIT return status ignored
82 cleanup() {
83 echo "cleanup [$@]"
84 return 42
85 }
86 trap 'cleanup x y z' EXIT
87 ## stdout: cleanup [x y z]
88 ## status: 0
89
90 #### trap EXIT with PARSE error
91 trap 'echo FAILED' EXIT
92 for
93 ## stdout: FAILED
94 ## status: 2
95 ## OK mksh status: 1
96
97 #### trap EXIT with PARSE error and explicit exit
98 trap 'echo FAILED; exit 0' EXIT
99 for
100 ## stdout: FAILED
101 ## status: 0
102
103 #### trap EXIT with explicit exit
104 trap 'echo IN TRAP; echo $stdout' EXIT
105 stdout=FOO
106 exit 42
107
108 ## status: 42
109 ## STDOUT:
110 IN TRAP
111 FOO
112 ## END
113
114 #### trap EXIT with command sub / subshell / pipeline
115 trap 'echo EXIT TRAP' EXIT
116
117 echo $(echo command sub)
118
119 ( echo subshell )
120
121 echo pipeline | cat
122
123 ## STDOUT:
124 command sub
125 subshell
126 pipeline
127 EXIT TRAP
128 ## END
129
130 #### trap ERR
131 err() {
132 echo "err [$@] $?"
133 }
134 trap 'err x y' ERR
135
136 echo A
137
138 false
139 echo B
140
141 ( exit 42 )
142 echo C
143
144 trap - ERR # disable trap
145
146 false
147 echo D
148
149 trap 'echo after errexit $?' ERR
150
151 set -o errexit
152
153 ( exit 99 )
154 echo E
155
156 ## status: 99
157 ## STDOUT:
158 A
159 err [x y] 1
160 B
161 err [x y] 42
162 C
163 D
164 after errexit 99
165 ## END
166 ## N-I dash STDOUT:
167 A
168 B
169 C
170 D
171 ## END
172
173 #### trap ERR and pipelines (lastpipe and PIPESTATUS difference)
174 case $SH in dash) exit ;; esac
175
176 err() {
177 echo "err [$@] status=$? [${PIPESTATUS[@]}]"
178 }
179 trap 'err' ERR
180
181 echo A
182
183 false
184
185 # succeeds
186 echo B | grep B
187
188 # fails
189 echo C | grep zzz
190
191 echo D | grep zzz | cat
192
193 set -o pipefail
194 echo E | grep zzz | cat
195
196 trap - ERR # disable trap
197
198 echo F | grep zz
199 echo ok
200
201 ## STDOUT:
202 A
203 err [] status=1 [1]
204 B
205 err [] status=1 [0 1]
206 err [] status=1 [0 1 0]
207 ok
208 ## END
209
210 # lastpipe semantics mean we get another call!
211 # also we don't set PIPESTATUS unless we get a pipeline
212
213 ## OK osh STDOUT:
214 A
215 err [] status=1 []
216 B
217 err [] status=1 [0 0]
218 err [] status=1 [0 1]
219 err [] status=1 [0 1 0]
220 ok
221 ## END
222
223 ## N-I dash STDOUT:
224 ## END
225
226 #### error in trap ERR (recursive)
227 case $SH in dash) exit ;; esac
228
229 err() {
230 echo err status $?
231 ( exit 2 )
232 }
233 trap 'err' ERR
234
235 echo A
236 false
237 echo B
238
239 ## STDOUT:
240 A
241 err status 1
242 B
243 ## END
244 ## N-I dash STDOUT:
245 ## END
246
247 #### trap 0 is equivalent to EXIT
248 # not sure why this is, but POSIX wants it.
249 trap 'echo EXIT' 0
250 echo status=$?
251 trap - EXIT
252 echo status=$?
253 ## status: 0
254 ## STDOUT:
255 status=0
256 status=0
257 ## END
258
259 #### trap 1 is equivalent to SIGHUP; HUP is equivalent to SIGHUP
260 trap 'echo HUP' SIGHUP
261 echo status=$?
262 trap 'echo HUP' HUP
263 echo status=$?
264 trap 'echo HUP' 1
265 echo status=$?
266 trap - HUP
267 echo status=$?
268 ## status: 0
269 ## STDOUT:
270 status=0
271 status=0
272 status=0
273 status=0
274 ## END
275 ## N-I dash STDOUT:
276 status=1
277 status=0
278 status=0
279 status=0
280 ## END
281
282 #### eval in the exit trap (regression for issue #293)
283 trap 'eval "echo hi"' 0
284 ## STDOUT:
285 hi
286 ## END
287
288
289 #### exit codes for traps are isolated
290
291 trap 'echo USR1 trap status=$?; ( exit 42 )' USR1
292
293 echo before=$?
294
295 # Equivalent to 'kill -USR1 $$' except OSH doesn't have "kill" yet.
296 # /bin/kill doesn't exist on Debian unless 'procps' is installed.
297 sh -c "kill -USR1 $$"
298 echo after=$?
299
300 ## STDOUT:
301 before=0
302 USR1 trap status=0
303 after=0
304 ## END
305
306 #### traps are cleared in subshell (started with &)
307
308 # Test with SIGURG because the default handler is SIG_IGN
309 #
310 # If we use SIGUSR1, I think the shell reverts to killing the process
311
312 # https://man7.org/linux/man-pages/man7/signal.7.html
313
314 trap 'echo SIGURG' URG
315
316 kill -URG $$
317
318 # Hm trap doesn't happen here
319 { echo begin child; sleep 0.1; echo end child; } &
320 kill -URG $!
321 wait
322 echo "wait status $?"
323
324 # In the CI, mksh sometimes gives:
325 #
326 # USR1
327 # begin child
328 # done
329 #
330 # leaving off 'end child'. This seems like a BUG to me?
331
332 ## STDOUT:
333 SIGURG
334 begin child
335 end child
336 wait status 0
337 ## END