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
|