Bash: Как сделать завершающие подпроцессы script, когда script завершается?

Вопрос относится к script, например:

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!"

Текущее поведение

Нажатие Ctrl+C в консоли завершает процессы script, но не уже запущенные процессы grep.

Ответ 1

Напишите ловушку для Ctrl+c, а в ловушке уничтожьте все подпроцессы. Поместите это перед вашей командой wait.

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

trap handle_sigint SIGINT

Ответ 2

Простая альтернатива - это использование трубы cat. Для меня работали следующие:

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

Если я нажму Ctrl-C до того, как последнее число будет напечатано на stdout. Он также работает, если команда генерации текста - это то, что занимает много времени, например "find/", т.е. Это не только соединение с stdout через cat, которое убито, но фактически дочерний процесс.

Для больших сценариев, которые широко используют подпроцессы, самый простой способ обеспечить отступ с положением Ctrl-C - обертывание всего script в такую ​​подоболочку, например

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

Я не уверен, хотя, если это имеет тот же эффект, что и ответ Andrew (т.е. я не уверен, какой сигнал отправляется на подпроцессы). Также я тестировал это только с cygwin, а не с родной оболочкой Linux.