シェル関数でタイムアウト その2

先日,シェルスクリプトタイムアウト用の関数を作ってみたのですが,計測したアプリケーションは,デーモンのような挙動をするプロセスでした.先日のスクリプトでは,内部で起動したプロセスのpidを見ています.ですが,デーモンの場合,起動したら,子プロセスを作成して,親プロセスは,さっさと終了してしまいます.そのため,タイムアウト関数も監視対象のpidはいなくなっているので,正しく動作しなくなっていたのでした.

というわけで,だいぶadhocな実装になってしまいますが,対策として,pidではなくプロセス名で監視して,タイムアウト時にkillallで,そのプロセス名を持つプロセスを全滅させることにしました.おかげで副作用が強烈になったので,注意して使いましょう...

使い方は,前回は「timeout 5 sleep 10」でしたが,プロセス名対応版では,「timeout_name 5 sleep sleep 10」のように2番目の引数に,監視対象のプロセス名を入れてください.

#!/bin/sh

timeout()
{
    count_timeout=$1
    shift 1;
    echo timeout: exec \'$@\'
    $@ &
    pid=$!
    count=0
    while [ $count -lt $count_timeout ]
    do
        isalive=`ps -ef | grep $pid | grep -v grep | wc -l`
        if [ $isalive -eq 1 ]; then
            echo timeout: $pid is alive.
            count=`expr $count + 1`
            sleep 1
        else
            echo timeout: $pid was disapeared.
            count=`expr $count_timeout`
        fi
    done
    isalive=`ps -ef | grep $pid | grep -v grep | wc -l`
    if [ $isalive = 1 ]; then
        kill -kill $pid
        wait $pid
        echo timeout: $pid was terminated by a SIG$(kill -l $?) signal.
    fi
}

timeout_name()
{
    count_timeout=$1
    pname=$2
    shift 2;
    echo timeout: $pname exec \'$@\'
    $@ &
    count=0
    while [ $count -lt $count_timeout ]
    do
        isalive=`ps -ef | grep $pname | grep -v grep | wc -l`
        if [ $isalive -ne 0 ]; then
	    echo timeout: $pname is alive.
	    count=`expr $count + 1`
	    sleep 1
        else
	    echo timeout: $pname was disapeared.
	    count=`expr $count_timeout`
        fi
    done
    isalive=`ps -ef | grep $pname | grep -v grep | wc -l`
    if [ $isalive -ne 0 ]; then
	killall -kill $pname
	echo timeout: $pname was terminated by a SIG$(kill -l $?) signal.
    fi
}