Як запровадити тайм-аут для сценаріїв оболонок?


35

Я хочу запустити скрипт оболонки, який має цикл у ньому, і він може тривати назавжди, чого я не хочу робити. Тому мені потрібно ввести тайм-аут для всього сценарію.

Як я можу ввести тайм-аут для всього сценарію оболонки під SuSE?


4
Це дуже розпливчасте питання. Чи можете ви, будь ласка, детальніше розказати про час очікування? Ви хочете, щоб тайм-аут був на весь сценарій, або тайм-аут на одну функцію чи команду? Що ви намагаєтесь зробити?
Тім Кеннеді

@TimKennedy: сподіваюся, що зараз краще.
Радек

1
Дивіться також Timing в сценарії оболонок (я не вважаю його дублікат з - за мою вимогу переносимості , який НЕ включає такі інструменти, як timeoutі expect)
Жиля SO- перестати бути злим »

Відповіді:


30

Якщо GNU timeoutнедоступний, ви можете використовувати expect(Mac OS X, BSD, ... зазвичай не мають за замовчуванням інструментів та утиліт GNU).

################################################################################
# Executes command with a timeout
# Params:
#   $1 timeout in seconds
#   $2 command
# Returns 1 if timed out 0 otherwise
timeout() {

    time=$1

    # start the command in a subshell to avoid problem with pipes
    # (spawn accepts one command)
    command="/bin/sh -c \"$2\""

    expect -c "set echo \"-noecho\"; set timeout $time; spawn -noecho $command; expect timeout { exit 1 } eof { exit 0 }"    

    if [ $? = 1 ] ; then
        echo "Timeout after ${time} seconds"
    fi

}

Приклад редагування :

timeout 10 "ls ${HOME}"

Виглядає добре. Як я бачу вихід команди, виконаної на екрані?
Радек

Привіт, вихід повинен бути видимим, оскільки stdout нікуди не перенаправляється. Я додав приклад використання. У моєму випадку він друкує вміст мого домашнього редактора, як очікувалося. Яка команда не друкує жодного виводу?
Маттео

Я не називав це належним чином. Це працює просто чудово! Дякую. Тільки він не виводить кількість секунд після таймауту.
Радек

@Radek Вибачте, виправлено
Маттео

1
Я хотів би підкреслити, що якщо використовувати тайм-аут GNU, сам стан повернення timeoutстановить 124 у випадку таймауту, інакше це стан повернення команди (про це йдеться у відповіді Тіма Кеннеді).
QuasarDonkey

15

Дякую за роз’яснення.

Найпростіший спосіб досягти того, що ви хочете, - це запустити свій скрипт із циклом в обгортці, як timeoutкоманда з пакету GNU Coreutils.

root@coraid-sp:~# timeout --help            
Usage: timeout [OPTION] DURATION COMMAND [ARG]...
   or: timeout [OPTION]
Start COMMAND, and kill it if still running after DURATION.

Mandatory arguments to long options are mandatory for short options too.
  -k, --kill-after=DURATION
                   also send a KILL signal if COMMAND is still running
                   this long after the initial signal was sent.
  -s, --signal=SIGNAL
                   specify the signal to be sent on timeout.
                   SIGNAL may be a name like 'HUP' or a number.
                   See `kill -l` for a list of signals
      --help     display this help and exit
      --version  output version information and exit

DURATION is an integer with an optional suffix:
`s' for seconds(the default), `m' for minutes, `h' for hours or `d' for days.

If the command times out, then exit with status 124.  Otherwise, exit
with the status of COMMAND.  If no signal is specified, send the TERM
signal upon timeout.  The TERM signal kills any process that does not
block or catch that signal.  For other processes, it may be necessary to
use the KILL (9) signal, since this signal cannot be caught.

Report timeout bugs to bug-coreutils@gnu.org
GNU coreutils home page: <http://www.gnu.org/software/coreutils/>
General help using GNU software: <http://www.gnu.org/gethelp/>
For complete documentation, run: info coreutils 'timeout invocation'

Зрештою, це буде набагато простіше, ніж написати власну функцію тайм-ауту, до якої оболонки, як правило, не мають вбудованого.


Я не зрозумів одразу, що це було встановлено, тому що він викликається gtimeoutв моїй установці (OSX).
Джошуа Голдберг

7

Запустіть сторожовий процес із вашого сценарію, щоб знищити його батьків, якщо він працює занадто довго. Приклад:

# watchdog process
mainpid=$$
(sleep 5; kill $mainpid) &
watchdogpid=$!

# rest of script
while :
do
   ...stuff...
done
kill $watchdogpid

Цей сценарій буде припинено сторожовою собакою через п'ять секунд.


6
Але вам доведеться чекати очікування кожного разу. У вашому прикладі ваш сценарій завжди буде працювати 5 секунд, навіть якщо сценарій значно коротший. Ви також повинні зберігати PID сторожової собаки та вбивати її наприкінці.
Маттео

@Matteo Ярмарок досить. Додано.
Кайл Джонс

1
Зауважте, що це може бути складніше, ніж це, залежно від того, що ... речі ... роблять. Дивіться Час вичерпання в сценарії оболонки
Жил "SO- перестаньте бути злим"

читайте також: як довго можна вважати PID унікальними stackoverflow.com/questions/11323410/linux-pid-recycling
Флоріан Кастеллан

3

Там також cratimeoutМартін Кракауер.

# cf. http://www.cons.org/cracauer/software.html
# usage: cratimeout timeout_in_msec cmd args
cratimeout 5000 sleep 600
cratimeout 5000 tail -f /dev/null
cratimeout 5000 sh -c 'while sleep 1; do date; done'

2
#!/bin/sh

# Execute a command with a timeout

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.