To add a few points to the above answers:
- Starting the process in the background with '&' and wait for its pid as advised by @cuonglm will make it possible for the handler to execute while the child is running, but the child will loose the ability to catch any input as stdin will be closed as soon as the child is detached. To force stdin to stay open, you might add an infinite loop which you pipe to the child process. See this post.
Then read input in the current shell and write it to the proc file of the child's process so it goes to its stdin:
(while true; do sleep 10000; done) | /bin/start/main/server --nodaemon &
child_pid=$!
while :
do
result=$(kill -0 $mypid > /dev/null 2>&1)
if [ $? -ne 0 ] ; then
# process is gone
break
else
# read input in the current shell and store it in a variable. The timeout only works with Bash, not with Bourne-Shell. You will need to find a way to read stdin instead and sleep 1 sec between each loop
read -t 1 input
# echo the input to the proc file of the runuser process so it goes to its stdin
echo $input > /proc/$child_pid/fd/0 2>/dev/null
fi
done
wait $child_pid
NOTE: this works pretty well on Linux but might need some adjustments for other Unix platforms.
EDIT: a simpler method is to duplicate stdin to a file descriptor which can then be used as the stdin for the background process:
exec 3<&0
/bin/start/main/server --nodaemon <&3 &
exec is the second solution as suggested by @Stuart P. Bentley, but sometimes you need to create the process with a new PID or the command used might not let you the choice and create the process with a new PID or even a new PGID (that's the case for example for runuser with the -l option).
An alternative to 1) and 2) is to send the signal to the process group instead of targeting a specific PID.
This can be done by using kill with a minus (-) before the child's PID:
kill -TERM -$child_pid
Bash will indeed let you trap signals that are targeting a process group without needing to start the process in the background. This method will not loose the ability for the child process to read stdin. This is also a good solution if your child is running in a different process group as the handler will let you forward the signal to the child. Limitation is that other members of the group will also receive the signal, which might be a problem or not depending on the scenario.
wait
call is then needed? – iruvar Jul 26 '14 at 22:08wait
need for our script to ... wait for child process to finish. We want to be sure that our script only quit after child process is terminated. – cuonglm Jul 27 '14 at 08:05exec /bin/start/main/server --nodaemon
(in which case the shell process is replaced with the server process and you don't need to propagate any signals) or you use/bin/start/main/server --nodaemon &
, but thenexec
is not really meaningful. – Andreas Veithen Nov 13 '14 at 19:39exec
from mid-script, so the Bash process will remain around the server process for cleanup on signal. – Stuart P. Bentley Mar 07 '15 at 04:27exec
is a perfectly reasonable solution for the problem as the original question was asked; I've submitted it as a separate answer, and clarified what this answer does instead. – Stuart P. Bentley Apr 14 '15 at 01:55exec command &
will start command in a subshell and in new shellexec
will replace the shell with the main program. I don't remember when the last edit remove exec part, make my explanation incorrect. – cuonglm Apr 14 '15 at 02:37_term()
function you shouldwait "$child"
again. This might be necessary if you have some other supervising process waiting for the shell script to die before restarting it again, or if you also trappedEXIT
to do some cleanup and neeed it to run only after the child process has finished. – LeoRochael May 08 '17 at 22:54bash
ignores SIGTERM only ininteractive
mode according toman
and my local testing. Otherwise good answer. – akostadinov Jun 26 '17 at 10:48set -o forwardsignals
, or whatever – Alexander Mills Sep 28 '18 at 18:07exec
, or you want to set up traps. – Stuart P. Bentley Sep 29 '18 at 16:06child=$!
, the child is not set and the kill reports error. To fix the trap handler should just use$!
– Igor Bukanov Nov 19 '18 at 09:49