Timeout команда в 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 можна перенаправляти так само, як якщо б це було бігати безпосередньо?

Якщо так, будь ласка, поділіться своїм кодом. Якщо ні, поясніть, будь ласка, чому.

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


5
Ще одне подібне запитання: stackoverflow.com/questions/526782/… (але я думаю, що відповідь "timeout3" тут набагато краща).
система ПАУЗА

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 працює ще довше!
система ПАУЗА

7
Вам не доведеться вибирати інтервал опитування, у нього за замовчуванням 1s, що дуже добре. А перевірка дуже недорога, накладні витрати незначні. Сумніваюсь, це зробить tlrbsf помітно довше. Я перевірив режим сну 30, і я отримав різницю в 0,000 мс між його використанням і нею.
Джуліано

6
Правильно, я зараз це бачу. І це відповідає моїм точним вимогам, якщо встановити інтервал опитування == timeout. Також працює в трубопроводах, працює з усією фоновою справою, працює з декількома екземплярами та виконує інші завдання. Солодке, дякую!
система ПАУЗА

Відправлення сигналу вбиває підрозділ, тому я подумав, що підшивка всіх команд вбити в одному рядку збереже їх. Я також увімкнув більш жорсткий вихід для відображення несподіваних помилок. stackoverflow.com/questions/687948 / ...
вугра ghEEz

1
@Juliano Це прекрасний спосіб вирішити тайм-аути, дуже корисний. Цікаво, чи існує спосіб, яким ми можемо мати сценарій повернення вихідного коду 143, коли процес буде вбито після таймауту? Я спробував додати "вихід 143" відразу після команди kill, але завжди отримую код виходу 0 у скрипті виклику.
Салман А. Кагзі

528

Ви, мабуть, шукаєте timeoutкоманду в coreutils. Оскільки він є частиною coreutils, технічно це рішення C, але це все ще coreutils. info timeoutдля отримання детальної інформації. Ось приклад:

timeout 5 /path/to/slow/command with options

21
В Mac ви можете встановити це через Macports або homebrew.
Іван З. Сіу

23
При встановленні через homebrew на OS X команда стаєgtimeout
ethicalhack3r

5
... яку ОС ви використовуєте, яка має coreutils до 2003 року?
Кіт


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

Оглядач вбиває вашу команду після заданого тайм-ауту; сценарій чекає повільного завдання і припиняє спостерігача. Зауважте, що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а потім перевірити, чи $watcherіснує Pid, ​​якщо він є, то ви знаєте, що ви не закінчилися.
Джордж Хокінс

Я не можу зрозуміти, чому це використовується killв одному випадку, а pkillв іншому. Мені потрібно було використовувати pkillобидва, щоб зробити цю роботу правильно. Я б очікував, що якщо ви завершите команду (), вам знадобиться pkillїї вбити. Але, можливо, це працює інакше, якщо всередині однієї команди є лише одна команда ().
nobar

Бог вас благословить, сер :)
Дарко Мілетич

22

Ось так:

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

ви можете змінити SIGINTі 10як хочете;)


3
"timeout" є частиною пакету coreutils на (принаймні) Redhat, Centos, Suse та Ubuntu, тому вам потрібно буде встановити його, якщо у вас його немає.
Аком

це дуже корисно !!!!!! Чи знаєте ви, чому іноді не працює "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`; ) }

Примітки:

  • Строго кажучи , вам не потрібно ;в ; ), однак він робить речі більш послідовні в ; }-случай. І, 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.


1
Баш 4 скелі. Це все.
система ПАУЗА

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
Ben Reser

17

Я віддаю перевагу "timelimit", який має пакет принаймні в debian.

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

Це трохи приємніше, ніж «тайм-аут» coreutils, тому що він друкує щось при знищенні процесу, а також надсилає SIGKILL через деякий час за замовчуванням.


Здається, це не дуже добре працює: / $ час timelimit -T2 сон 10 реальних 0m10.003s користувач 0m0.000s sys 0m0.000s
hithwen

3
Використовуйте -t2 не -T2. Великий -T - час від надсилання SIGTERM до надсилання SIGKILL.
макси

1
Я хотів би додати, що timelimit 1.8 не працює добре з вилкою ( timelimit -t1 ./a_forking_progвбийте лише один з двох процесів), але час роботи працює.
Джеремі Кохой

Якщо ви хочете затримати час, щоб надрукувати щось під час вбивства процесу, просто використовуйте прапор "-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. Ви можете сміливо припускати в будь-якому випадку , проте, стався якийсь тайм-аут.


9

Дивіться також http://www.pixelbeat.org/scripts/timeout скрипт, функціонал якого інтегрований у новіші основні програми


Акуратний, простий, використовує термін і не вбиває. Приємно! Я досліджував подібне рішення для пастки / очікування, коли спочатку ставив питання.
система ПАУЗА

тайм-аут повертає 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

(ls -ltR / cygdrive / c / windows & SPID = $ {!}; (сон 1 s; вбити $ {SPID}) & CPID = $ {!}; fg 1; вбити $ {CPID})> fdsa
система ПАУЗА

bash: fg: немає контролю за роботою
система PAUSE

@ система PAUSE, встановити -m, я думаю.
страгер

Я маю контроль роботи (set -m) в оболонці входу. Це "м" у вмісті himBH в $ -, але воно, здається, зникає для підрозділів. Можливо, артефакт Сігвіна. бурчання
система ПАУЗА

Не використовуйте "fg" у сценаріях. Прочитайте "допомогти почекати".
lhunath

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

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

Це прекрасно працює, якщо я називаю еталонні процеси із системними дзвінками.


2
Це вбиває інші процеси, які трапляються з використанням цього імені, і не вбиває процес із заданим іменем, якщо воно змінює своє ім'я (наприклад, написання argv[0], можливо, з іншими хаками, щоб зробити більше місця).
Джед

Я знайшов варіацію цього зручного під час спроби зупинити докер-контейнери через певний час. Клієнт докера, схоже, не прийняв 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'

"Зокрема, він зберігає сигнальну поведінку." Приємно мати такий варіант!
система ПАУЗА

1

OS X ще не використовує bash 4, а також не має / usr / bin / timeout, тому ось функція, що працює на OS X без домашньої пивоварні чи макпортів, схожа на / 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
) }

0

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

Ваш процес звисає чи ламається через n секунд? Потім з’ясуйте, чому, і замість цього виправте.

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


4
Маючи доступ до 100% джерела (і більшості обладнання, наприклад мережевих комутаторів), я погоджуюся, що, ймовірно, є кращі рішення, ніж час очікування. Але коли 'tlrbsf' є закритим джерелом, лише бінарним, іноді вам доведеться обійти це обмеження.
система ПАУЗА

@lhunath, "у сценаріях у вас немає контролю над роботою (і намагатися ввімкнути це нерозумно)" - Будь ласка, уточнюйте тут: stackoverflow.com/questions/690266/…
система ПАУЗА

@system PAUSE: Відповісти stackoverflow.com/questions/690266 / ... правильно, я також прокоментував це.
lhunath

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


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 Вибачте, я забув, чому я змінив лінію завершення процесу і чому я вважав, що це важливо поділитися. Шкода, що я цього не записав. Можливо, я виявив, що мені потрібно зробити паузу, перш ніж перевірити на успіх вбивства-ТЕРМ. Сценарій 2008 року з кухарської книги, схоже, перевіряє стан процесу відразу після надсилання SIGTERM, що, можливо, призводить до помилки при спробі надіслати SIGKILL процесу, який загинув.
вугор gEEz

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 для виділення псевдотерміналу, тому він діє як інтерактивна оболонка


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 ...

Якщо ви хочете затримати процес і замовкнути роботу вбивства / pid, запустіть:

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

Це ставить фоновий процес у підзарядку, щоб ви не бачили вихідну роботу.


-3

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

Я використовую:

scripttimeout -t 60 /script.php

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