Bash: How do I make sub-processes of a script be terminated, when the script is terminated?
Asked Answered
K

2

11

The question applies to a script such as the following:

Script

#!/bin/sh

SRC="/tmp/my-server-logs"

echo "STARTING GREP JOBS..."
for f in `find ${SRC} -name '*log*2011*' | sort --reverse`
do
    (
        OUT=`nice grep -ci -E "${1}" "${f}"`
        if [ "${OUT}" != "0" ]
        then
            printf '%7s : %s\n' "${OUT}" "${f}"
        else
            printf '%7s   %s\n' "(none)" "${f}"
        fi
    ) &
done

echo "WAITING..."
wait

echo "FINISHED!"

Current behavior

Pressing Ctrl+C in console terminates the script but not the already running grep processes.

Katheykathi answered 19/10, 2011 at 7:0 Comment(0)
K
16

Write a trap for Ctrl+c and in the trap kill all of the subprocesses. Put this before your wait command.

function handle_sigint()
{
    for proc in `jobs -p`
    do
        kill $proc
    done
}

trap handle_sigint SIGINT
Kiser answered 19/10, 2011 at 7:34 Comment(5)
Thank you! Works great! Except that my bash expected function before handle_sigint.Katheykathi
I've added function to the script.Kiser
Well, here's a problem: when the script is ran on hundreds of files, not all processes are started at once (which is good). Sadly, this leads to termination of only a fraction of processes on Ctrl+C. I suppose, during termination inside the trap loop, others are getting started. Suggestions? (Moving the trap and its function before the main loop doesn't help)Katheykathi
#360701 looks useful. trap "kill 0" SIGINT works on my machine.Kiser
Note: the first line of your script needs to read #!/bin/bash, not #!/bin/sh, for this to work.Unchain
A
0

A simple alternative is using a cat pipe. The following worked for me:

echo "-" > test.text; 
for x in 1 2 3; do 
    ( sleep $x; echo $x | tee --append test.text; ) & 
done | cat

If I press Ctrl-C before the last number is printed to stdout. It also works if the text-generating command is something that takes a long time such as "find /", i.e. it is not only the connection to stdout through cat that is killed but actually the child process.

For large scripts that make extensive use of subprocesses the easiest way to ensure the indented Ctrl-C behaviour is wrapping the whole script into such a subshell, e.g.

#!/usr/bin/bash
(
    ...
) | cat

I am not sure though if this has the exactly same effect as Andrew's answer (i.e. I'm not sure what signal is sent to the subprocesses). Also I only tested this with cygwin, not with a native Linux shell.

Attainture answered 7/2, 2014 at 14:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.