Outils pour utilisateurs

Outils du site


tuto:linux:script_timeout_en_shell

Timeout en SHELL

timeout.sh

#!/bin/sh
 
# Execute a command with a timeout
 
# Author:
#    http://www.pixelbeat.org/
# Notes:
#    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.
#    Note there is a timeout command packaged with coreutils since v7.0
#    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
("$@" || exit $?)& 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
./timeout.sh 2 sleep 4

Un autre script s'appuyant sur timeout.sh permettant de lancer des processus à la volée avec des timeout :

#!/bin/bash
 
dir_result="/root/results"
 
declare -a command command_pid
 
usage() {
        echo "Usage : $0 <command1>,<timeout> <command2>,<command3>"
        exit 1
}
 
kill_proc() {
        for pid in ${command_pid[*]}; do
                [ -d /proc/$pid ] && [ `grep $0 /proc/${pid}/cmdline | wc -l` -ne 0 ] && kill -9 $pid && echo -e "$pid tué"
        done
}
 
while getopts :h OPTION
do
        case "$OPTION" in
             h)
                usage
                ;;
        esac
done
 
 
nb_arg=`echo "$@" | awk -F\, '{ print NF }'`
 
[ ! -d $dir_result ] && mkdir -p "$dir_result"
 
echo "Table des processus :"
 
for ((i=1; i<=$nb_arg; i+=1))
do
        log=`expr $i - 1`
        cmd=`echo "$@" | awk -v nb=$i -F\, '{ print $nb }' | sed s/^' '*//g`
 
        command[${#command[*]}]=$cmd
 
        if [ `echo "$cmd" | awk '{ print $1 }' | grep "^[[:digit:]]" | wc -l` -gt 0 ] ; then
                timeout=`echo "$cmd" | awk '{ print $1 }'`
        fi
 
        if [ -z $timeout ] ; then
                (
                        $cmd 2>&1 1>$dir_result/$log
                        ret=$?
                        sleep 0.1
                        echo "$! : Fait ($ret)"
                        [ $ret -ne 0 ] && exit 1
                ) &
        else
                (
                        `dirname $0`/timeout.sh $cmd 2>&1 1>$dir_result/$log
                        ret=$?
                        sleep 0.1
                        if [ $ret -eq 0 ] ; then
                                echo "$! : Fait ($ret)"
                        else if [ $ret -eq 124 ] ; then
                                echo "$! : Timeout"
                                exit 1
                        else
                                echo  "$! : Fait($ret) !"
                                exit 1
                        fi
                        fi
                ) &
 
                unset timeout
        fi
 
        command_pid[${#command_pid[*]}]=$!
done
 
for i in ${!command[*]}
do
        if [ `echo ${command[i]} | awk '{ print $1 }' | grep "^[[:digit:]]" | wc -l` -gt 0 ] ; then
                echo "${command_pid[i]} : `echo ${command[i]} | cut -d ' ' -f 2-` - timeout(`echo ${command[i]} | awk '{ print $1 }'`)"
        else
                echo "${command_pid[i]} : ${command[i]}"
        fi
done
 
echo ""
 
trap 'kill_proc' 2 3 15
 
wait
 
for i in ${!command[*]}
do
        [ -f "$dir_result/$i" ] && mv "$dir_result/$i" "$dir_result/${command_pid[i]}"
done
tuto/linux/script_timeout_en_shell.txt · Dernière modification: 2013/03/12 23:13 par root