В GNU coreutils есть программа 'timeout', которую можно легко скомпилировать для MacOS X (я нашел ее на своем компьютере в поисках собственной одноименной программы).
В качестве альтернативы, у меня есть версия, которую я написал примерно в 1989 году. Для правильной работы на MacOS X потребовалось несколько приемов. ( Свяжитесь со мной, если вам нужен код - см. Мой профиль .)
Вот сценарий оболочки, который приблизительно соответствует тому, что вы хотите.Он не может удовлетворить все ваши требования: в частности, он не может надежно ретранслировать состояние выхода.Он уже достаточно искривлен, чтобы сделать программу на C тривиальной.Оболочка (bash, во всяком случае) не помогает, если не переоценивать «$$» (текущий идентификатор процесса) для подоболочек;он по-прежнему полагает, что идентификатор процесса суб-оболочек совпадает с родительским процессом.
#!/bin/bash
# timeout -t time [-s signal] cmd [arg ...]
usage()
{
echo "Usage: $(basename $0 .sh) -t time [-s signal] cmd [arg ...]" 1>&2
exit 1
}
signal=15
while getopts t:s: opt "$@"
do
case $opt in
(t) time=$OPTARG;;
(s) signal=$OPTARG;;
(*) usage;;
esac
done
shift $((OPTIND - 1))
[ $# -ne 0 ] || usage
[ -n "$time" ] || usage
pid_top=$$
# Run the command
(
("$@") &
pid_sub=$!
echo $pid_sub > .pid.$pid_top
trap "kill $signal $pid_sub 2>/dev/null;
kill 15 $pid_top 2>/dev/null; exit 1" 15
wait
kill $signal $pid_top 2>/dev/null
) &
pid_shell=$!
pid_cmd=$(cat .pid.$pid_top; rm -f .pid.$pid_top)
# Watchdog timer
(sleep $time; kill $signal $pid_cmd 2>/dev/null;
kill -15 $pid_shell $pid_top) &
pid_watch=$!
# Cleanup!
trap "kill $signal $pid_cmd 2>/dev/null;
kill 15 $pid_shell $pid_watch 2>/dev/null; exit 1" 15
wait
Логика обработки аргументов в основном стандартная - вы должны указать время, вы можете указать сигнал, вынеобходимо указать команду, вы можете указать аргументы для этой команды.
Основной сценарий оболочки отмечает собственный идентификатор процесса в переменной pid_top для удобства вложенных оболочек (хотя '$$', вероятно, будет работать).
Затем основная оболочка запускает фоновую вложенную оболочку для запуска команды, но здесь необходимы махинации.Сначала вспомогательная оболочка выполняет фактическую команду в фоновом режиме, захватывая идентификатор подпроцесса в pid_sub.Затем он передает этот PID в файл '.pid. $ Pid_top', чтобы родительская оболочка могла прочитать его и организовать отправку угроз смерти фактической команде, если время ожидания истекло.Затем он организует захват сигнала 15 (SIGTERM);при получении такого сигнала он убивает фактическую команду с помощью сигнала, запрошенного в командной строке, а также отправляет сигнал завершения родительскому процессу.Тогда это уходит в ожидание.Если команда завершается, она отправляет сигнал завершения родительскому процессу, сообщая родителю, что все в порядке.
Вернувшись в основную оболочку, она записывает идентификатор процесса фоновой подоболочки в pid_shell итакже фактической команды в pid_cmd.Затем запускается еще одна вложенная оболочка - сторожевой процесс.Сторожевой таймер организует спящие в течение периода ожидания, а когда это время истекло, отправляет сигнал фактической команде и сигнал завершения родительскому процессу.
Итак, теперь в фоновом режиме работают три процесса.(ой - это сбивает с толку);текущая команда, вспомогательная оболочка, ожидающая выполнения команды, и сторожевой таймер.
Основная оболочка захватывает PID сторожевого таймера и организует перехват сигнала 15. При получении сигнала он отправляетсоответствующий сигнал завершения для фактической команды и сигнал завершения для вспомогательной оболочки и сторожевого таймера, даже если хотя бы один из них не существует.
Основная оболочка наконец переходит в ожидание своейдети умирают.На самом деле он никогда не возвращается после этого ожидания;сигнал разбудит его, и ловушка выполнится, но в результате он зависнет до тех пор, пока не прекратятся процессы.
Затем он завершится ...
Чтобы получить точный статус от выполненногоКоманда сложная.Проблема в том, что если оболочка запускает процесс в фоновом режиме, вы не можете получить его состояние выхода;но если вы запустите его синхронно (чтобы вы могли получить статус выхода), тогда сторожевой таймер и основной процесс не будут знать свой PID и не смогут гарантировать его завершение, когда закончится таймер.Возможно, я просто упускаю очевидное - я, безусловно, надеюсь, потому что этот сценарий ужасен!Для себя я буду придерживаться C-программы;он использует только два процесса и возвращает актуальный статус команды.