Actually it did print, but you have to wait 100 seconds to see the result.
You said:
$./test.sh > output &
[4] 42624
If you check ps aux, you will get something similar to:
xiaobai 42624 0.0 0.1 118788 5492 pts/3 S 04:07 0:00 /bin/bash
xiaobai 42626 0.0 0.0 108192 668 pts/3 S 04:07 0:00 sleep 100
Your main script process of /bin/bash, PID 42624 still waiting for sleep 100 finish. Even main process received signal 1, it have to wait sleep 100 finished first, after that is its turn to perform its task, i.e. echo "cleaning up!".
You can make sleep process become background process. In this case, script process can perform echo "cleaning up!" without waiting the sleep process, if and only if script process doesn't exit yet.
We can proved the conceptual(i.e. script is waiting sleep before handle signal) via this script:
function clean_up {
echo "cleaning up!"
}
echo 'starting!'
trap clean_up SIGHUP
sleep 5000 &
echo 1
sleep 20
echo 2
sleep 10
echo 3
Run this script by ./test.sh > output as usual, then use ps aux to figure out the /bin/bash PID is 23311, then do kill -1 23311. In the same time cat output to know the stage, i.e. when the script go into sleep 20 after echo 1, send kill -1 23311, now wait for 2 come out, you will notice "cleaning up" has been print together before 2. Finally is the turn of echo 3 and the script exit.
$ cat output
starting!
1
cleaning up!
2
3
$
The experiment above proved that script receive the signal SIGHUP and perform the signal handler after all previous foreground process is done and to its turn, without waiting the background process.
The story become interesting, with your original script, what if you do kill -1 PID_of_sleep_100 ?
It will exit all processes without print, because the sleep process doesn't return SIGHUP to script process.
So there's a solution to your task, you can do kill -1 PPID(script process) to acknowledge SIGHUP to script process, then kill -1 PID(sleep process). Now script process will do SIGHUP handler before exit, happy hacking :)
Not all signals is same, e.g. SIGKILL is not allow to trap. If you kill -9 the script process, then sleep process will still running and its parent PID will become 1 (check by ps -ef).
[UPDATE]:
Normally kill -N script_PID will kill directly the script if the signal N doesn't trap in your script. But be careful about SIGINT, kill -2 script_PID will not directly kill even though your script doesn't trap it. Your script will wait your child process(e.g. sleep 10) done. Now assume you do multiple kill in script_PID, i.e. kill -2 script_PID AND kill -user-defined_trap_N script_PID, then:
- If sleep return normally by after wait for 10 seconds OR kill by signal other than 2, your script will ignore cached signal 2 when return, then perform the user-defined_trap_N function.
- But if sleep kill by signal 2, then your script will perform the builtin SIGINT handler when return, then kill directly without perform user-defined_trap_N.
sleep 100but something that won't necessarily ever return, likewait_on(BSD)? How do you kill the script? Specifically if it is an RC script, the start/stop mechanism relies onkill -TERMstopping the script. – user9645 Jun 18 '20 at 14:58tr '%' $'\n' > trap.sh <<< '#!/bin/bash%trap "echo This is SIGTERM; exit 99" TERM%echo Starting as $$%sleep 100%echo Enough%'then run itbash trap.sh &. Now wait a little while and thenkill -TERM pid, replacingpidwith the PID reported by the script. – Chris Davies Jun 18 '20 at 15:25