Тайм-аут команды в bash без лишней задержки

283

Этот ответ на команду командной строки для автоматического уничтожения команды через определенное время

предлагает 1-строчный метод для тайм-аута длительной команды из командной строки bash:

( /path/to/slow command with options ) & sleep 5 ; kill $!

Но возможно, что данная «длительная» команда может завершиться раньше, чем время ожидания. (Давайте назовем это «обычно продолжительной, но иногда быстрой» командой или tlrbsf для удовольствия.)

Так что у этого изящного подхода с 1 линией есть пара проблем. Во-первых, sleepэто не условно, так что устанавливает нежелательную нижнюю границу времени, необходимого для завершения последовательности. Рассмотрим 30 с, 2 м или даже 5 м для сна, когда команда tlrbsf заканчивается через 2 секунды, что крайне нежелательно. Во-вторых, killэто безусловное условие, поэтому эта последовательность попытается убить не запущенный процесс и скулить по этому поводу.

Так...

Есть ли способ для тайм-аута обычно длительной, но иногда быстрой ( "tlrbsf" ) команды, которая

  • имеет реализацию bash (на другой вопрос уже есть ответы на Perl и C)
  • будет завершен в более раннем из двух: завершение программы tlrbsf или истекло время ожидания
  • не будет уничтожать несуществующие / не запущенные процессы (или, опционально: не будет жаловаться на неудачное уничтожение)
  • не должен быть 1-лайнер
  • может работать под Cygwin или Linux

... и, для получения бонусных очков, запускает команду tlrbsf на переднем плане и любой «спящий» или дополнительный процесс в фоновом режиме, так что stdin / stdout / stderr команды tlrbsf может быть перенаправлен так же, как если бы он был бежать напрямую?

Если это так, пожалуйста, поделитесь своим кодом. Если нет, объясните, пожалуйста, почему.

Я потратил некоторое время, пытаясь взломать вышеупомянутый пример, но я достигаю предела своих навыков в bash.

системная пауза
источник
5
Другой похожий вопрос: stackoverflow.com/questions/526782/… (но я думаю, что ответ 'timeout3' здесь намного лучше).
система PAUSE
2
Есть ли причина не использовать timeoutутилиту gnu ?
Крис Джонсон
timeoutотлично! Вы даже можете использовать несколько команд (многострочный скрипт): stackoverflow.com/a/61888916/658497
Ноам Манос

Ответы:

149

Я думаю, что это именно то, что вы просите:

http://www.bashcookbook.com/bashinfo/source/bash-4.0/examples/scripts/timeout3

#!/bin/bash
#
# The Bash shell script executes a command with a time-out.
# Upon time-out expiration SIGTERM (15) is sent to the process. If the signal
# is blocked, then the subsequent SIGKILL (9) terminates it.
#
# Based on the Bash documentation example.

# Hello Chet,
# please find attached a "little easier"  :-)  to comprehend
# time-out example.  If you find it suitable, feel free to include
# anywhere: the very same logic as in the original examples/scripts, a
# little more transparent implementation to my taste.
#
# Dmitry V Golovashkin <Dmitry.Golovashkin@sas.com>

scriptName="${0##*/}"

declare -i DEFAULT_TIMEOUT=9
declare -i DEFAULT_INTERVAL=1
declare -i DEFAULT_DELAY=1

# Timeout.
declare -i timeout=DEFAULT_TIMEOUT
# Interval between checks if the process is still alive.
declare -i interval=DEFAULT_INTERVAL
# Delay between posting the SIGTERM signal and destroying the process by SIGKILL.
declare -i delay=DEFAULT_DELAY

function printUsage() {
    cat <<EOF

Synopsis
    $scriptName [-t timeout] [-i interval] [-d delay] command
    Execute a command with a time-out.
    Upon time-out expiration SIGTERM (15) is sent to the process. If SIGTERM
    signal is blocked, then the subsequent SIGKILL (9) terminates it.

    -t timeout
        Number of seconds to wait for command completion.
        Default value: $DEFAULT_TIMEOUT seconds.

    -i interval
        Interval between checks if the process is still alive.
        Positive integer, default value: $DEFAULT_INTERVAL seconds.

    -d delay
        Delay between posting the SIGTERM signal and destroying the
        process by SIGKILL. Default value: $DEFAULT_DELAY seconds.

As of today, Bash does not support floating point arithmetic (sleep does),
therefore all delay/time values must be integers.
EOF
}

# Options.
while getopts ":t:i:d:" option; do
    case "$option" in
        t) timeout=$OPTARG ;;
        i) interval=$OPTARG ;;
        d) delay=$OPTARG ;;
        *) printUsage; exit 1 ;;
    esac
done
shift $((OPTIND - 1))

# $# should be at least 1 (the command to execute), however it may be strictly
# greater than 1 if the command itself has options.
if (($# == 0 || interval <= 0)); then
    printUsage
    exit 1
fi

# kill -0 pid   Exit code indicates if a signal may be sent to $pid process.
(
    ((t = timeout))

    while ((t > 0)); do
        sleep $interval
        kill -0 $$ || exit 0
        ((t -= interval))
    done

    # Be nice, post SIGTERM first.
    # The 'exit 0' below will be executed if any preceeding command fails.
    kill -s SIGTERM $$ && kill -0 $$ || exit 0
    sleep $delay
    kill -s SIGKILL $$
) 2> /dev/null &

exec "$@"
Жулиано
источник
Это хитрый трюк, использующий $$ для фоновой части. И приятно, что он немедленно убьет зависшего tlrbsf. Но ты должен выбрать интервал опроса. И если вы установите слишком низкий уровень опроса, он будет загружать процессор с постоянной сигнализацией, заставляя tlrbsf работать еще дольше!
система PAUSE
7
Вам не нужно выбирать интервал опроса, по умолчанию он равен 1 с, что довольно хорошо. И проверка очень недорогая, накладные расходы незначительны. Я сомневаюсь, что это заставит tlrbsf работать заметно дольше. Я проверил со сном 30, и получил разницу 0,000ms между использованием и не использованием.
Джулиано
6
Хорошо, я вижу это сейчас. И это точно соответствует моим требованиям, если вы установите интервал опроса == тайм-аут. Также работает в конвейерах, работает с фоном, работает с несколькими экземплярами и другими запущенными заданиями. Сладкий, спасибо!
система PAUSE
Отправка сигнала уничтожает вложенную оболочку, поэтому я подумал, что выравнивание всех команд kill на одной строке сохранит их. Я также включил вывод stderr для отображения неожиданных ошибок. stackoverflow.com/questions/687948/…
угорь ghEEz
1
@Juliano Это отличный способ справиться с таймаутами, очень полезный. Интересно, есть ли способ, которым мы можем получить код возврата сценария возврата 143, когда процесс завершается после истечения времени ожидания? Я попытался добавить «выход 143» сразу после команды kill, но всегда получаю код выхода 0 в скрипте вызывающей программы.
Салман А. Кагзи
529

Вы, вероятно, ищете timeoutкоманду в coreutils. Поскольку это часть coreutils, технически это решение на C, но это все еще coreutils. info timeoutБольше подробностей. Вот пример:

timeout 5 /path/to/slow/command with options
yingted
источник
21
В Mac вы можете установить это через Macports или homebrew.
Иван З. Сиу
23
При установке через доморощенный на OS X команда становитсяgtimeout
ethicalhack3r
5
... в какой ОС вы используете coreutils до 2003 года?
Кит
5
@Keith: CentOS 5.10, например :-(
приостановлено до дальнейшего уведомления.
9
Для пояснения, команда homebrew, которая вам нужна в OSX / Mac, есть brew install coreutils, и тогда вы можете ее использовать gtimeout.
Охад Шнайдер
37

Это решение работает независимо от режима мониторинга bash. Вы можете использовать правильный сигнал для завершения вашей_команды

#!/bin/sh
( your_command ) & pid=$!
( sleep $TIMEOUT && kill -HUP $pid ) 2>/dev/null & watcher=$!
wait $pid 2>/dev/null && pkill -HUP -P $watcher

Наблюдатель убивает your_command после заданного времени ожидания; скрипт ожидает медленной задачи и завершает работу наблюдателя. Обратите внимание, что waitне работает с процессами, которые являются потомками другой оболочки.

Примеры:

  • your_command выполняется более 2 секунд и был прерван

ваша_команда прервана

( sleep 20 ) & pid=$!
( sleep 2 && kill -HUP $pid ) 2>/dev/null & watcher=$!
if wait $pid 2>/dev/null; then
    echo "your_command finished"
    pkill -HUP -P $watcher
    wait $watcher
else
    echo "your_command interrupted"
fi
  • ваша_команда завершена до истечения времени ожидания (20 секунд)

ваша_команда завершена

( sleep 2 ) & pid=$!
( sleep 20 && kill -HUP $pid ) 2>/dev/null & watcher=$!
if wait $pid 2>/dev/null; then
    echo "your_command finished"
    pkill -HUP -P $watcher
    wait $watcher
else
    echo "your_command interrupted"
fi
Дмитрий
источник
1
waitвозвращает состояние завершения процесса, которого он ожидает. Таким образом, если ваша команда завершает работу в течение выделенного времени, но с ненулевым состоянием выхода, тогда логика будет вести себя так, как истекло время ожидания, то есть печатать your_command interrupted. Вместо этого вы можете обойтись waitбез ifи затем проверить, существует ли $watcherpid, если он есть, то вы знаете, что время не истекло.
Джордж Хокинс
Я не могу понять, почему это используется killв одном случае, но pkillв другом. Мне нужно было использовать pkillоба, чтобы сделать это правильно. Я ожидаю, что если вы добавите команду (), вам придется использовать ее pkillдля уничтожения. Но, возможно, это работает по-другому, если в. Есть только одна команда ().
Нобар
Да благословит вас Бог, сэр :)
Дарко Милетик
22

Там вы идете:

timeout --signal=SIGINT 10 /path/to/slow command with options

Вы можете изменить SIGINTи 10по своему желанию;)

Ариан П. Алеахмад
источник
3
«timeout» является частью пакета coreutils (по крайней мере) для Redhat, Centos, Suse и Ubuntu, поэтому вам нужно установить его, если у вас его нет.
Аком
это действительно полезно !!!!!! Знаете ли вы, почему yingted «timeout 5 / path / to / slow / command with options» иногда не работает?
Декула
К сожалению, этого нет в coreutilsпакете на FreeBSD.
Пол Биссекс
18

Вы можете сделать это полностью с bash 4.3и выше:

_timeout() { ( set +b; sleep "$1" & "${@:2}" & wait -n; r=$?; kill -9 `jobs -p`; exit $r; ) }
  • Пример: _timeout 5 longrunning_command args
  • Пример: { _timeout 5 producer || echo KABOOM $?; } | consumer
  • Пример: producer | { _timeout 5 consumer1; consumer2; }
  • Пример: { while date; do sleep .3; done; } | _timeout 5 cat | less

  • Нужен Bash 4.3 для wait -n

  • Дает 137, если команда была убита, иначе возвращаемое значение команды.
  • Работает для труб. (Вам не нужно выходить на передний план здесь!)
  • Работает также с внутренними командами или функциями оболочки.
  • Запускается в подоболочке, поэтому нет экспорта переменных в текущую оболочку, извините.

Если вам не нужен код возврата, это можно сделать еще проще:

_timeout() { ( set +b; sleep "$1" & "${@:2}" & wait -n; kill -9 `jobs -p`; ) }

Ноты:

  • Строго говоря, вы не нуждаетесь в ;in ; ), однако это делает вещь более последовательной для ; }-case. И, set +bвероятно, тоже можно оставить, но лучше, чем потом сожалеть.

  • За исключением --forground(возможно) вы можете реализовать все варианты timeoutподдержки. --preserve-statusэто немного сложно, хотя. Это оставлено в качестве упражнения для читателя;)

Этот рецепт может быть использован "естественно" в оболочке (так же естественно, как для flock fd):

(
set +b
sleep 20 &
{
YOUR SHELL CODE HERE
} &
wait -n
kill `jobs -p`
)

Однако, как объяснялось выше, вы не можете реэкспортировать переменные окружения в оболочку естественным образом.

Редактировать:

Пример из реальной жизни: Тайм-аут __git_ps1в случае, если он занимает слишком много времени (для таких вещей, как медленные SSHFS-ссылки):

eval "__orig$(declare -f __git_ps1)" && __git_ps1() { ( git() { _timeout 0.3 /usr/bin/git "$@"; }; _timeout 0.3 __orig__git_ps1 "$@"; ) }

Edit2: исправление. Я заметил, что exit 137не нужен и делает _timeoutненадежным одновременно.

Edit3: gitтвердолобый, поэтому для удовлетворительной работы нужен двойной трюк.

Edit4: забыл _в первом _timeoutдля реального мира примере GIT.

Tino
источник
1
Баш 4 скалы. Вот и все.
система PAUSE
1
Это на самом деле требует Bash 4.3 или новее. cc. The 'wait' builtin has a new '-n' option to wait for the next child to change status. От: tiswww.case.edu/php/chet/bash/NEWS
Бен Резер,
17

Я предпочитаю "timelimit", который имеет пакет, по крайней мере, в Debian.

http://devel.ringlet.net/sysutils/timelimit/

Это немного лучше, чем «таймаут» для coreutils, потому что он печатает что-то, когда убивает процесс, а также отправляет SIGKILL через некоторое время по умолчанию.

Maxy
источник
Кажется, это не очень хорошо работает: / $ time timelimit -T2 sleep 10 real 0m10.003s user 0m0.000s sys 0m0.000s
hithwen
3
Используйте -t2, а не -T2. Большое -T - это время от отправки SIGTERM до отправки SIGKILL.
maxy
1
Я хотел бы добавить, что timelimit 1.8 не работает хорошо с fork ( timelimit -t1 ./a_forking_progубить только один из двух процессов), но timeout работает.
Джереми Кохой
Если вы хотите, чтобы тайм-аут печатал что-то при завершении процесса, просто используйте флаг "-v".
10

Для тайм-аута slowcommandчерез 1 секунду:

timeout 1 slowcommand || echo "I failed, perhaps due to time out"

Чтобы определить, истек ли срок действия команды или произошел сбой по ее собственным причинам, проверьте, имеет ли код состояния 124:

# ping for 3 seconds, but timeout after only 1 second
timeout 1 ping 8.8.8.8 -w3
EXIT_STATUS=$?
if [ $EXIT_STATUS -eq 124 ]
then
echo 'Process Timed Out!'
else
echo 'Process did not timeout. Something else went wrong.'
fi
exit $EXIT_STATUS

Обратите внимание, что когда состояние выхода равно 124, вы не знаете, истекло ли оно из-за вашей timeoutкоманды или сама команда завершилась из-за какой-то внутренней логики тайм-аута, а затем вернула 124. Вы можете смело предполагать в любом случае Тем не менее, произошел какой-то тайм-аут.

lance.dolan
источник
9

Смотрите также http://www.pixelbeat.org/scripts/timeout скрипт, функциональность которого была интегрирована в более новые coreutils

pixelbeat
источник
Аккуратный, простой, использует TERM, а не KILL. Ницца! Я искал решение «ловушка / ожидание», как это, когда я первоначально поставил вопрос.
система PAUSE
Тайм-аут возвращает 124 в случае убийства.
празднование
8

Вроде хак, но это работает. Не работает, если у вас есть другие процессы переднего плана (пожалуйста, помогите мне исправить это!)

sleep TIMEOUT & SPID=${!}; (YOUR COMMAND HERE; kill ${SPID}) & CPID=${!}; fg 1; kill ${CPID}

На самом деле, я думаю, что вы можете отменить это, отвечая вашим «бонусным» критериям:

(YOUR COMMAND HERE & SPID=${!}; (sleep TIMEOUT; kill ${SPID}) & CPID=${!}; fg 1; kill ${CPID}) < asdf > fdsa
strager
источник
(ls -ltR / cygdrive / c / windows & SPID = $ {!}; (sleep 1s; kill $ {SPID}) & CPID = $ {!}; fg 1; kill $ {CPID})> fdsa
системная PAUSE
bash: fg: нет управления заданиями
система PAUSE
@ ПАУЗА системы, установите -m, я думаю.
Страгер
У меня есть контроль задания (set -m) в оболочке входа в систему. Это «m» в содержимом himBH в $ -, но, похоже, оно исчезает для подоболочек. Возможно, артефакт Cygwin. ворчание
система PAUSE
Не используйте «fg» в сценариях. Читайте «помогите подождать».
28
8

Тайм-аут , вероятно, первый подход, чтобы попробовать. Вам может потребоваться уведомление или другая команда для выполнения, если она истекает. После долгих поисков и экспериментов я придумал сценарий bash :

if 
    timeout 20s COMMAND_YOU_WANT_TO_EXECUTE;
    timeout 20s AS_MANY_COMMANDS_AS_YOU_WANT;
then
    echo 'OK'; #if you want a positive response
else
    echo 'Not OK';
    AND_ALTERNATIVE_COMMANDS
fi
user2099484
источник
5

Простой скрипт с понятностью кода. Сохранить в /usr/local/bin/run:

#!/bin/bash

# run
# Run command with timeout $1 seconds.

# Timeout seconds
timeout_seconds="$1"
shift

# PID
pid=$$

# Start timeout
(
  sleep "$timeout_seconds"
  echo "Timed out after $timeout_seconds seconds"
  kill -- -$pid &>/dev/null
) &
timeout_pid=$!

# Run
"$@"

# Stop timeout
kill $timeout_pid &>/dev/null

Тайм-аут команды, которая выполняется слишком долго:

$ run 2 sleep 10
Timed out after 2 seconds
Terminated
$

Заканчивается сразу для команды, которая завершает:

$ run 10 sleep 2
$

источник
3

Если вы уже знаете имя программы (предположим program), что она завершается после истечения времени ожидания (в качестве примера, 3секунд), я могу предложить простое и несколько грязное альтернативное решение:

(sleep 3 && killall program) & ./program

Это прекрасно работает, если я вызываю тестовые процессы с помощью системных вызовов.

Loup
источник
2
Это убивает другие процессы, которые используют имя, и не убивает процесс с заданным именем, если он меняет свое имя (например, путем записи в argv[0], возможно, с другими хаки, чтобы освободить место).
Джед
Я нашел вариант этого удобного, когда пытался остановить докер контейнеров через определенное время. Docker-клиент, похоже, не принимал TERM / INT / KILL таким образом, чтобы фактически остановить контейнер, который запускался на переднем плане. Так что присвоение имени контейнеру и его использование (sleep 3 && docker stop <container>) &работало хорошо. Спасибо!
Мат Шаффер
да, он грязный и ограниченный, но может быть улучшен следующим образом: { sleep 5 && kill -9 $(ps -fe | grep "program" | grep $$ | tr -s " " | cut -d" " -f2); } & SLEEPPID=$!; bash -c "program" && kill -9 $SLEEPPID"таким образом, он будет убивать только рабочие места в текущей оболочке.
тонна
2

Есть также cratimeoutМартин Кракауэр (написан на C для систем Unix и Linux).

# cf. http://www.cons.org/cracauer/software.html
# usage: cratimeout timeout_in_msec cmd args
cratimeout 5000 sleep 1
cratimeout 5000 sleep 600
cratimeout 5000 tail -f /dev/null
cratimeout 5000 sh -c 'while sleep 1; do date; done'
max32
источник
«В частности, это сохраняет поведение сигнала». Приятно иметь такую ​​возможность!
система PAUSE
1

OS X пока не использует bash 4 и не имеет / usr / bin / timeout, так что вот функция, которая работает в OS X без home-brew или macports, которая похожа на / usr / bin / timeout (основана на Tino's ответ). Проверка параметров, помощь, использование и поддержка других сигналов - упражнение для читателя.

# implement /usr/bin/timeout only if it doesn't exist
[ -n "$(type -p timeout 2>&1)" ] || function timeout { (
    set -m +b
    sleep "$1" &
    SPID=${!}
    ("${@:2}"; RETVAL=$?; kill ${SPID}; exit $RETVAL) &
    CPID=${!}
    wait %1
    SLEEPRETVAL=$?
    if [ $SLEEPRETVAL -eq 0 ] && kill ${CPID} >/dev/null 2>&1 ; then
      RETVAL=124
      # When you need to make sure it dies
      #(sleep 1; kill -9 ${CPID} >/dev/null 2>&1)&
      wait %2
    else
      wait %2
      RETVAL=$?
    fi
    return $RETVAL
) }
NerdMachine
источник
0

В 99% случаев ответ НЕ для реализации какой-либо логики тайм-аута. Тайм - аут логика почти в любой ситуации красный предупреждающий знак , что что - то еще не так и должно быть исправлено вместо .

Ваш процесс иногда зависает или прерывается через n секунд? Затем выясните причину и исправьте это.

Кроме того, для правильного решения проблемы strager вам нужно использовать wait "$ SPID" вместо fg 1, так как в сценариях у вас нет управления заданиями (и пытаться включить его глупо). Более того, fg 1 основывается на том факте, что вы ранее не запускали никаких других заданий в сценарии, что является неверным предположением.

lhunath
источник
4
Имея доступ к 100% источника (и большей части аппаратного обеспечения, такого как сетевые коммутаторы), я бы согласился с тем, что, вероятно, есть лучшие решения, чем тайм-аут. Но когда tlrbsf является закрытым исходным кодом, только двоичным, иногда вам приходится обходить это ограничение.
система PAUSE
@lhunath, «в сценариях у вас нет управления заданиями (и пытаться включить его глупо)» - уточните здесь: stackoverflow.com/questions/690266/…
system PAUSE
@system PAUSE: Ответ stackoverflow.com/questions/690266/… правильный, я тоже прокомментировал это.
лунат
29
Лхунат, то, что ты говоришь, не имеет смысла. Есть множество случаев, когда тайм-аут является хорошим вариантом, например, в любое время, когда вам нужно перейти по сети.
Нейт Мюррей,
Исключение: вы пишете тестовые сценарии, чтобы проверить, не было ли у уже запущенного программного обеспечения проблемы тайм-аута.
Петер - Восстановить Монику
0

Мне представили проблему с сохранением контекста оболочки и разрешением тайм-аутов, единственная проблема в том, что он остановит выполнение скрипта по тайм-ауту - но это соответствует потребностям, которые мне были представлены:

#!/usr/bin/env bash

safe_kill()
{
  ps aux | grep -v grep | grep $1 >/dev/null && kill ${2:-} $1
}

my_timeout()
{
  typeset _my_timeout _waiter_pid _return
  _my_timeout=$1
  echo "Timeout($_my_timeout) running: $*"
  shift
  (
    trap "return 0" USR1
    sleep $_my_timeout
    echo "Timeout($_my_timeout) reached for: $*"
    safe_kill $$
  ) &
  _waiter_pid=$!
  "$@" || _return=$?
  safe_kill $_waiter_pid -USR1
  echo "Timeout($_my_timeout) ran: $*"
  return ${_return:-0}
}

my_timeout 3 cd scripts
my_timeout 3 pwd
my_timeout 3 true  && echo true || echo false
my_timeout 3 false && echo true || echo false
my_timeout 3 sleep 10
my_timeout 3 pwd

с выходами:

Timeout(3) running: 3 cd scripts
Timeout(3) ran: cd scripts
Timeout(3) running: 3 pwd
/home/mpapis/projects/rvm/rvm/scripts
Timeout(3) ran: pwd
Timeout(3) running: 3 true
Timeout(3) ran: true
true
Timeout(3) running: 3 false
Timeout(3) ran: false
false
Timeout(3) running: 3 sleep 10
Timeout(3) reached for: sleep 10
Terminated

конечно, я предполагаю, что там был режиссер scripts

mpapis
источник
0
#! /bin/bash
timeout=10
interval=1
delay=3
(
    ((t = timeout)) || :

    while ((t > 0)); do
        echo "$t"
        sleep $interval
        # Check if the process still exists.
        kill -0 $$ 2> /dev/null || exit 0
        ((t -= interval)) || :
    done

    # Be nice, post SIGTERM first.
    { echo SIGTERM to $$ ; kill -s TERM $$ ; sleep $delay ; kill -0 $$ 2> /dev/null && { echo SIGKILL to $$ ; kill -s KILL $$ ; } ; }
) &

exec "$@"
угорь боже
источник
@Tino Извините, я забыл, почему я изменил строку завершения процесса и почему я думал, что это важно поделиться. Жаль, что я не записал это. Возможно, я обнаружил, что мне нужно сделать паузу, прежде чем проверять успешность команды kill -s TERM. Сценарий 2008 года из поваренной книги, кажется, проверяет состояние процесса сразу после отправки SIGTERM, что может привести к ошибке при попытке отправить SIGKILL процессу, который умер.
угорь ghEEz
0

Моя проблема была, возможно, немного другой: я запускаю команду через ssh на удаленной машине и хочу уничтожить оболочку и дочерние элементы, если команда зависает.

Теперь я использую следующее:

ssh server '( sleep 60 && kill -9 0 ) 2>/dev/null & my_command; RC=$? ; sleep 1 ; pkill -P $! ; exit $RC'

Таким образом, команда возвращает 255 при истечении времени ожидания или кода возврата команды в случае успеха

Обратите внимание, что процессы уничтожения в ssh-сессии обрабатываются не так, как в интерактивной оболочке. Но вы также можете использовать опцию -t для ssh для выделения псевдотерминала, поэтому он действует как интерактивная оболочка

Franky_GT
источник
0

Вот версия, которая не основана на порождении дочернего процесса - мне нужен был автономный скрипт, который встраивал эту функцию. Это также делает интервал частичного опроса, так что вы можете опрашивать быстрее. тайм-аут был бы предпочтительным - но я застрял на старом сервере

# wait_on_command <timeout> <poll interval> command
wait_on_command()
{
    local timeout=$1; shift
    local interval=$1; shift
    $* &
    local child=$!

    loops=$(bc <<< "($timeout * (1 / $interval)) + 0.5" | sed 's/\..*//g')
    ((t = loops))
    while ((t > 0)); do
        sleep $interval
        kill -0 $child &>/dev/null || return
        ((t -= 1))
    done

    kill $child &>/dev/null || kill -0 $child &>/dev/null || return
    sleep $interval
    kill -9 $child &>/dev/null
    echo Timed out
}

slow_command()
{
    sleep 2
    echo Completed normally
}

# wait 1 sec in 0.1 sec increments
wait_on_command 1 0.1 slow_command

# or call an external command
wait_on_command 1 0.1 sleep 10
Нил МакГилл
источник
-1

Очень упрощенный способ:

# command & sleep 5; pkill -9 -x -f "command"

с помощью pkill (опция -f ) вы можете уничтожить вашу конкретную команду с аргументами или указать -n, чтобы избежать уничтожения старого процесса.

Фрэнсис
источник
Вы понимаете, что это, по сути, то, что ОП имеет в своем посте и что он указывает, что он не хочет, верно? Потому что он всегда ждет полной задержки сна.
Этан Рейснер
-1

Опираясь на ответ @ loup ...

Если вы хотите отключить процесс и отключить вывод kill / pid, выполните:

( (sleep 1 && killall program 2>/dev/null) &) && program --version 

Это помещает фоновый процесс в подоболочку, поэтому вы не видите выходных данных задания.

Коди А. Рэй
источник
-3

У меня есть работа cron, которая вызывает скрипт php, и иногда он застревает на скрипте php. Это решение было идеальным для меня.

Я использую:

scripttimeout -t 60 /script.php
Джехад Буриа
источник
1
Что такое scripttimeout?
rudolfbyker