20

Windows の CYGWIN で実行している BASH スクリプトを長時間実行しています。

スクリプトの実行を 30 秒に制限し、この制限を超えると自動的に終了したいと考えています。理想的には、これを任意のコマンドで実行できるようにしたいと考えています。

例えば:

sh-3.2$ limittime -t 30 'myscript.sh'

また

sh-3.2$ limittime -t 30 'grep func *.c'

cygwin では、ulimit コマンドが機能しないようです。

私はどんなアイデアにもオープンです。

4

5 に答える 5

18

http://www.pixelbeat.org/scripts/timeoutスクリプトを参照してください。その機能は新しい coreutils に統合されています。

#!/bin/sh

# Execute a command with a timeout

# License: LGPLv2
# Author:
#    http://www.pixelbeat.org/
# Notes:
#    Note there is a timeout command packaged with coreutils since v7.0
#    If the timeout occurs the exit status is 124.
#    There is an asynchronous (and buggy) equivalent of this
#    script packaged with bash (under /usr/share/doc/ in my distro),
#    which I only noticed after writing this.
#    I noticed later again that there is a C equivalent of this packaged
#    with satan by Wietse Venema, and copied to forensics by Dan Farmer.
# Changes:
#    V1.0, Nov  3 2006, Initial release
#    V1.1, Nov 20 2007, Brad Greenlee <brad@footle.org>
#                       Make more portable by using the 'CHLD'
#                       signal spec rather than 17.
#    V1.3, Oct 29 2009, Ján Sáreník <jasan@x31.com>
#                       Even though this runs under dash,ksh etc.
#                       it doesn't actually timeout. So enforce bash for now.
#                       Also change exit on timeout from 128 to 124
#                       to match coreutils.
#    V2.0, Oct 30 2009, Ján Sáreník <jasan@x31.com>
#                       Rewritten to cover compatibility with other
#                       Bourne shell implementations (pdksh, dash)

if [ "$#" -lt "2" ]; then
    echo "Usage:   `basename $0` timeout_in_seconds command" >&2
    echo "Example: `basename $0` 2 sleep 3 || echo timeout" >&2
    exit 1
fi

cleanup()
{
    trap - ALRM               #reset handler to default
    kill -ALRM $a 2>/dev/null #stop timer subshell if running
    kill $! 2>/dev/null &&    #kill last job
      exit 124                #exit with 124 if it was running
}

watchit()
{
    trap "cleanup" ALRM
    sleep $1& wait
    kill -ALRM $$
}

watchit $1& a=$!         #start the timeout
shift                    #first param was timeout for sleep
trap "cleanup" ALRM INT  #cleanup after timeout
"$@"& wait $!; RET=$?    #start the job wait for it and save its return value
kill -ALRM $a            #send ALRM signal to watchit
wait $a                  #wait for watchit to finish cleanup
exit $RET                #return the value
于 2010-02-02T12:41:32.193 に答える
12

次のスクリプトは、バックグラウンドタスクを使用してこれを行う方法を示しています。最初のセクションは、10秒の制限の後に60秒のプロセスを強制終了します。2番目の試みは、すでに終了しているプロセスを強制終了します。タイムアウトを非常に高く設定すると、プロセスIDがロールオーバーして、間違ったプロセスを強制終了する可能性があることに注意してください。ただし、これは理論上の問題です。タイムアウトは非常に大きくする必要があり、多くのプロセスを開始します。

#!/usr/bin/bash

sleep 60 &
pid=$!
sleep 10
kill -9 $pid

sleep 3 &
pid=$!
sleep 10
kill -9 $pid

Cygwinボックスの出力は次のとおりです。

$ ./limit10
./limit10: line 9:  4492 Killed sleep 60
./limit10: line 11: kill: (4560) - No such process

プロセスが終了するまで待つだけの場合は、ループに入って確認する必要があります。sleep 1他のコマンドは実際には1秒以上かかります(ただし、それほど長くはかかりません)。このスクリプトを使用して、上記の2番目のセクションを置き換えます(「echo $proc」および「date」コマンドはデバッグ用であり、最終的なソリューションに含まれるとは思われません)。

#!/usr/bin/bash

date
sleep 3 &
pid=$!
((lim = 10))
while [[ $lim -gt 0 ]] ; do
    sleep 1
    proc=$(ps -ef | awk -v pid=$pid '$2==pid{print}{}')
    echo $proc
    ((lim = lim - 1))
    if [[ -z "$proc" ]] ; then
            ((lim = -9))
    fi
done
date
if [[ $lim -gt -9 ]] ; then
    kill -9 $pid
fi
date

基本的にループし、プロセスがまだ毎秒実行されているかどうかを確認します。そうでない場合は、子を殺そうとしないように特別な値でループを終了します。そうでなければ、それはタイムアウトになり、子供を殺します。

sleep 3これが:の出力です。

Mon Feb  9 11:10:37 WADT 2009
pax 4268 2476 con 11:10:37 /usr/bin/sleep
pax 4268 2476 con 11:10:37 /usr/bin/sleep
Mon Feb  9 11:10:41 WADT 2009
Mon Feb  9 11:10:41 WADT 2009

sleep 60

Mon Feb  9 11:11:51 WADT 2009
pax 4176 2600 con 11:11:51 /usr/bin/sleep
pax 4176 2600 con 11:11:51 /usr/bin/sleep
pax 4176 2600 con 11:11:51 /usr/bin/sleep
pax 4176 2600 con 11:11:51 /usr/bin/sleep
pax 4176 2600 con 11:11:51 /usr/bin/sleep
pax 4176 2600 con 11:11:51 /usr/bin/sleep
pax 4176 2600 con 11:11:51 /usr/bin/sleep
pax 4176 2600 con 11:11:51 /usr/bin/sleep
pax 4176 2600 con 11:11:51 /usr/bin/sleep
pax 4176 2600 con 11:11:51 /usr/bin/sleep
Mon Feb  9 11:12:03 WADT 2009
Mon Feb  9 11:12:03 WADT 2009
./limit10: line 20:  4176 Killed sleep 60
于 2009-02-09T00:55:24.700 に答える
5

このリンクをチェックしてください。アイデアはmyscript.sh、スクリプトのサブプロセスとして実行し、その PID を記録し、実行時間が長すぎる場合は強制終了するというものです。

于 2009-02-09T00:44:10.513 に答える
2

コマンドをバックグラウンド ジョブとして (つまり、「&」を使用して) 実行し、「最後のコマンド実行の pid」に bash 変数を使用し、必要な時間だけスリープしてから、killその pid で実行することができます。

于 2009-02-09T00:42:04.170 に答える