How to handle signals in bash during synchronous execution?

I have a bash script process that at some point executes a lengthy subprocess synchronously. During the execution of this subprocess, the signal is sent directly to the bash script process with a request to complete the script. Is there a way to intercept this signal, terminate the subprocess, and then exit the bash process?

Does bash signal processing ever interrupt synchronous calls?

I can not control the fact that the completion signal is sent to the bash process. Although, if the signal can propagate to the child process, this will also solve my problem.

thanks in advance broes

+6
source share
3 answers

See the bash man page for the SIGNALS section:

If bash waits for the completion of the command and receives a signal for which a trap is set, the trap will not be executed until the command completes . When bash expects an asynchronous command through the built-in wait, receiving a signal for which a trap is set will cause wait builtin to immediately return with an exit status of more than 128, immediately after which the trap is executed.

So, start your external program asynchronously and use wait. Kill him using $ !.

+7
source

This uses the bash utility function that I wrote for processing. It has proven useful and reliable. I hope you find this helpful.

# Run a command in a way that can be interrupted by a signal (eg SIGTERM) # # When bash receives a SIGTERM it normally simply exits. If it executing a subprocess # that subprocess isn't signaled. (Typically that not a problem for interactive shells # because the entire Process Group gets sent the signal.) # # When running a script it sometimes useful for the script to propagate a SIGTERM # to the command that was running. We can do that by using the trap builtin to catch # the signal. But it a little tricky, per the bash manual: # # If bash is waiting for a command to complete and receives a signal for # which a trap has been set, the trap will not be executed until the # command completes. # # so a script executing a long-running command with a signal trap set won't # notice the signal until later. There a way around that though... # # When bash is waiting for an asynchronous command via the wait builtin, the # reception of a signal for which a trap has been set will cause the wait # builtin to return immediately with an exit status greater than 128, # immediately after which the trap is executed. # # Usage: # # interruptable [options] command [args] # # Options: # --killall - put the child into a process group (via setsid) # and send the SIGTERM to the process group # --debug - print a message including pid of the child # # Usage examples: # # interruptable sleep 3600 # # If not interrupted, the exit status of the specified command is returned. # If interrupted, the specified command is sent a SIGTERM and the current # shell exits with a status of 143. interruptable() { # handle options local setsid="" local debug=false while true; do case "${1:-}" in --killall) setsid=setsid; shift ;; --debug) debug=true; shift ;; --*) echo "Invalid option: $1" 1>&2; exit 1;; *) break;; # no more options esac done # start the specified command $setsid " $@ " & local child_pid=$! # arrange to propagate a signal to the child process trap ' exec 1>&2 set +e trap "" SIGPIPE # ensure a possible sigpipe from the echo does not prevent the kill echo "${BASH_SOURCE[0]} caught SIGTERM while executing $* (pid $child_pid), sending SIGTERM to it" # (race) child may have exited in which case kill will report an error # if setsid is used then prefix the pid with a "-" to indicate that the signal # should be sent to the entire process group kill ${setsid:+-}$child_pid exit 143 ' SIGTERM # ensure that the trap doesn't persist after we return trap 'trap - SIGTERM' RETURN $debug && echo "interruptable wait (child $child_pid, self $$) for: $*" # An error status from the child process will trigger an exception (via set -e) # here unless the caller is checking the return status wait $child_pid # last command, so status of waited for command is returned } 
+1
source

Yes, the signal can be intercepted by the trap command. See the example below:

 #!/bin/bash function wrap { local flag=0 trap "flag=1" SIGINT SIGTERM xeyes & subppid=$! while : do if [ $flag -ne 0 ] ; then kill $subppid break fi sleep 1 done } flag=0 trap "flag=1" SIGINT SIGTERM wrap & wrappid=$! while : # This is the same as "while true". do if [ $flag -ne 0 ] ; then kill $wrappid break fi sleep 1 # This script is not really doing anything. done echo 'end' 

What trap basically consists in is that it executes a command between "". So, the main function is in the while loop below. At each iteration, the script checks to see if the flag is set; if not, it sleeps for a second. Before that, we remembered the pid of the child process through $! . The trap issues a command when capturing SIGINT or SIGTERM (for other signals, see the kill manual).

The wrapper function does the same as the main function. In addition, it calls the actual subprocess function (in this case, the xeyes subprocess). When the wrapper function receives the SIGTERM signal from the main function (the main function also falls into one of the signals), the wrapper function can clear things up before the subprocess is actually destroyed. After that, it breaks out of the while loop and exits the wrapper function. Then the main function also breaks and prints 'end' .

edit: I hope I understand that correctly, you are forced to execute xeyes & . Then the steps will be as follows (in the terminal):

 xeyes & subpid=$! trap "kill $subpid && exit " SIGINT SIGTERM .... other stuff .... more stuff ^C #TERMINATE - this firstly kills xeyes and then exits the terminal 
0
source

Source: https://habr.com/ru/post/927551/


All Articles