Timeout di un comando in bash senza inutili ritardi


283

Questa risposta al comando da riga di comando per uccidere automaticamente un comando dopo un certo periodo di tempo

propone un metodo a 1 riga per il timeout di un comando di lunga durata dalla riga di comando bash:

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

Ma è possibile che un determinato comando "di lunga durata" possa terminare prima del timeout. (Chiamiamolo un comando "tipicamente long-running-ma-talvolta-veloce", o tlrbsf per divertimento.)

Quindi questo elegante approccio da 1 linea ha un paio di problemi. Innanzitutto, sleepnon è condizionale, quindi imposta un limite inferiore indesiderabile sul tempo impiegato per il completamento della sequenza. Considera 30s o 2m o anche 5m per il sonno, quando il comando tlrbsf termina in 2 secondi - altamente indesiderabile. In secondo luogo, ilkill è incondizionato, quindi questa sequenza tenterà di uccidere un processo non in esecuzione e gemere al riguardo.

Così...

C'è un modo per eseguire il timeout di un comando tipicamente long-running-ma-talvolta-fast ( "tlrbsf" ) che

  • ha un'implementazione bash (l'altra domanda ha già risposte Perl e C)
  • terminerà alla prima delle due: tlrbsf programma o timeout scaduto
  • non ucciderà i processi inesistenti / non in esecuzione (o, facoltativamente: non si lamenterà di una cattiva uccisione)
  • non deve essere un 1-liner
  • può funzionare con Cygwin o Linux

... e, per i punti bonus, esegue il comando tlrbsf in primo piano e qualsiasi " sospensione " o processo extra in background, in modo che lo stdin / stdout / stderr del comando tlrbsf possa essere reindirizzato, come se fosse stato correre direttamente?

In tal caso, condividi il tuo codice. Altrimenti, spiega perché.

Ho passato un po 'di tempo a cercare di hackerare l'esempio di cui sopra, ma sto colpendo il limite delle mie abilità di bash.


5
Un'altra domanda simile: stackoverflow.com/questions/526782/… (ma penso che la risposta 'timeout3' qui sia molto meglio).
sistema PAUSA

2
Qualche motivo per non usare l' timeoututilità gnu ?
Chris Johnson,

timeoutè grande! puoi persino usarlo con più comandi (script multilinea): stackoverflow.com/a/61888916/658497
Noam Manos

Risposte:


149

Penso che sia esattamente quello che stai chiedendo:

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 "$@"

Questo è un acuto trucco, usando $$ per la parte di sfondo. E bello che ucciderà immediatamente un tlrbsf sospeso. Ma devi scegliere un intervallo di polling. E se imposti un polling troppo basso, consumerà la CPU con un segnale costante, facendo funzionare tlrbsf ancora più a lungo!
sistema PAUSA

7
Non devi scegliere l'intervallo di polling, ha un valore predefinito di 1s, che è abbastanza buono. E il controllo è molto economico, l'overhead è trascurabile. Dubito che renderebbe tlrbsf notevolmente più lungo. Ho provato con il sonno 30 e ho ottenuto una differenza di 0.000 ms tra l'utilizzo e il non utilizzo.
Juliano

6
Bene, lo vedo adesso. E soddisfa i miei esatti requisiti se imposti l'intervallo di polling == timeout. Funziona anche in pipeline, funziona con tutto il background, funziona con più istanze e altri lavori in esecuzione. Dolce grazie!
sistema PAUSA

L'invio di un segnale uccide la sotto-shell, quindi ho pensato che il rivestimento di tutti i comandi kill su una riga li preservasse. Ho anche abilitato l'output di stderr per visualizzare errori imprevisti. stackoverflow.com/questions/687948/...
anguilla ghEEz

1
@Juliano È un ottimo modo per gestire i timeout, molto utile. Mi chiedo se c'è un modo in cui possiamo avere lo script return exitcode 143 quando il processo viene interrotto dopo il timeout? Ho provato ad aggiungere "exit 143" subito dopo il comando kill, ma ottengo sempre il codice di uscita 0 nello script del chiamante.
Salman A. Kagzi,

528

Probabilmente stai cercando il timeoutcomando in coreutils. Dal momento che fa parte dei coreutils, è tecnicamente una soluzione C, ma è ancora coreutils. info timeoutper ulteriori dettagli. Ecco un esempio:

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

21
In Mac puoi installarlo tramite Macports o homebrew.
Ivan Z. Siu,

23
Se installato tramite homebrew su OS X, il comando diventagtimeout
ethicalhack3r

5
... quale sistema operativo stai utilizzando con coreutils precedenti al 2003?
Keith,

5
@Keith: CentOS 5.10, ad esempio :-(
In pausa fino a ulteriore comunicazione.

9
Per chiarire, il comando homebrew necessario su OSX / mac è brew install coreutilse quindi è possibile utilizzare gtimeout.
Ohad Schneider,

37

Questa soluzione funziona indipendentemente dalla modalità monitor bash. Puoi usare il segnale corretto per terminare il tuo_comando

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

L'osservatore uccide il tuo_comando dopo un determinato timeout; lo script attende l'attività lenta e termina l'osservatore. Nota chewait non funziona con processi che sono figli di una shell diversa.

Esempi:

  • tuo_comando dura più di 2 secondi ed è stato terminato

tuo_comando interrotto

( 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
  • tuo_comando terminato prima del timeout (20 secondi)

tuo_comando finito

( 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
waitrestituisce lo stato di uscita del processo in attesa. Quindi se il tuo comando termina entro il tempo assegnato ma con uno stato di uscita diverso da zero, la logica qui si comporterà come è scaduto, cioè stampa your_command interrupted. Invece si potrebbe fare il waitsenza ife poi verificare se il $watcherpid esiste ancora, se lo fa, allora sai che non l'hai fatto timeout.
George Hawkins,

Non riesco a capire perché questo usi killin un caso ma pkillnell'altro. Avevo bisogno di usare pkillentrambi per far funzionare correttamente. Mi aspetto che se si avvolge un comando (), sarà necessario utilizzarlo pkillper ucciderlo. Ma forse funziona in modo diverso se c'è un solo comando all'interno di ().
nobar,

Dio ti benedica signore :)
Darko Miletic,

22

Ecco qua:

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

puoi cambiare SIGINTe 10come desideri;)


3
"timeout" fa parte del pacchetto coreutils su (almeno) Redhat, Centos, Suse e Ubuntu, quindi dovrai installarlo se non lo possiedi.
Akom,

è davvero utile !!!!!! Sai perché il "timeout 5 / path / to / slow / command di yingted a volte non funziona?
Decula,

Sfortunatamente questo non è nel coreutilspacchetto su FreeBSD.
Paul Bissex,

18

Puoi farlo interamente con bash 4.3e sopra:

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

  • Ha bisogno di Bash 4.3 per wait -n

  • Fornisce 137 se il comando è stato ucciso, altrimenti il ​​valore restituito dal comando.
  • Funziona per tubi. (Non è necessario andare in primo piano qui!)
  • Funziona anche con comandi o funzioni della shell interna.
  • Viene eseguito in una subshell, quindi nessuna esportazione variabile nella shell corrente, mi dispiace.

Se non è necessario il codice di ritorno, questo può essere reso ancora più semplice:

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

Appunti:

  • A rigor di termini non è necessario il ;in ; ), tuttavia rende le cose più coerenti al ; }caso. E anche il set +bprobabilmente può essere lasciato da parte, ma meglio prevenire che curare.

  • Ad eccezione di --forground(probabilmente) è possibile implementare tutti i timeoutsupporti varianti . --preserve-statusè un po 'difficile, però. Questo è lasciato come esercizio per il lettore;)

Questa ricetta può essere utilizzata "naturalmente" nel guscio (naturale come per flock fd):

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

Tuttavia, come spiegato sopra, non è possibile riesportare in modo naturale le variabili di ambiente nella shell inclusa.

Modificare:

Esempio nel mondo reale: timeout __git_ps1nel caso impieghi troppo tempo (per cose come collegamenti SSHFS lenti):

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

Edit2: Bugfix. Ho notato che exit 137non è necessario e rende _timeoutinaffidabile allo stesso tempo.

Edit3: gitè un duro da morire, quindi ha bisogno di un doppio trucco per funzionare in modo soddisfacente.

Edit4: dimenticato a _nel primo _timeoutesempio GIT nel mondo reale.


1
Bash 4 rocce. Questo è tutto.
sistema PAUSA

1
Questo in realtà richiede Bash 4.3 o versioni successive. cc. The 'wait' builtin has a new '-n' option to wait for the next child to change status. Da: tiswww.case.edu/php/chet/bash/NEWS
Ben Reser

17

Preferisco "timelimit", che ha un pacchetto almeno in debian.

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

È un po 'più bello del "timeout" dei coreutils perché stampa qualcosa quando si uccide il processo e invia anche SIGKILL dopo un po' di tempo per impostazione predefinita.


Non sembra funzionare abbastanza bene: / $ time timelimit -T2 sleep 10 real 0m10.003s user 0m0.000s sys 0m0.000s
hithwen

3
Usa -t2 non -T2. Il grande -T è il tempo dall'invio di SIGTERM fino all'invio di SIGKILL.
maxy,

1
Vorrei aggiungere che timelimit 1.8 non funziona correttamente con fork ( timelimit -t1 ./a_forking_proguccide solo uno dei due processi), ma il timeout funziona.
Jeremy Cochoy,

Se vuoi che il timeout stampi qualcosa quando uccidi il processo, usa semplicemente il flag "-v".

10

Per timeout slowcommanddopo 1 secondo:

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

Per determinare se il comando è scaduto o non è riuscito per i propri motivi, verificare se il codice di stato è 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

Nota che quando lo stato di uscita è 124, non sai se è scaduto a causa del tuo timeoutcomando o se il comando stesso è terminato a causa di una sua logica di timeout interna e quindi restituito 124. Puoi tranquillamente supporre in entrambi i casi , tuttavia, che si è verificato un timeout di qualche tipo.



8

Kinda hacky, ma funziona. Non funziona se hai altri processi in primo piano (per favore aiutami a risolvere questo problema!)

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

In realtà, penso che tu possa invertirlo, soddisfacendo i tuoi criteri di "bonus":

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

(ls -ltR / cygdrive / c / windows & SPID = $ {!}; (sleep 1s; kill $ {SPID}) & CPID = $ {!}; fg 1; kill $ {CPID})> fdsa
PAUSA di sistema

bash: fg: nessun controllo del lavoro
sistema PAUSA

@system PAUSE, set -m, penso.
Strager

Ho il controllo del lavoro (set -m) nella shell di login. Questa è la 'm' nei contenuti himBH di $ -, ma sembra scomparire per i subshells. Forse un manufatto Cygwin.brontolio
sistema PAUSA

Non usare "fg" negli script. Leggi "aiuto in attesa".
lhunath,

8

il timeout è probabilmente il primo approccio da provare. Potrebbe essere necessaria una notifica o un altro comando da eseguire in caso di timeout. Dopo un bel po 'di ricerca e sperimentazione, ho pensato a questo script 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

Script semplice con chiarezza del codice. Salva in /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

Timeout di un comando che dura troppo a lungo:

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

Termina immediatamente per un comando che completa:

$ run 10 sleep 2
$

3

Se conosci già il nome del programma (supponiamo program) da terminare dopo il timeout (ad esempio 3secondi), posso contribuire con una soluzione alternativa semplice e piuttosto sporca:

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

Funziona perfettamente se chiamo processi di benchmark con chiamate di sistema.


2
Questo uccide altri processi che usano il nome e non uccide il processo con il nome dato se cambia il suo nome (ad esempio scrivendo argv[0], forse con altri hack per fare più spazio).
Jed

Ho trovato utile una variante di questo quando ho cercato di arrestare i contenitori della finestra mobile dopo un certo periodo di tempo. Il client docker non sembrava accettare TERM / INT / KILL in un modo tale da arrestare effettivamente il contenitore in esecuzione in primo piano. Quindi dare un nome al contenitore e usarlo ha (sleep 3 && docker stop <container>) &funzionato bene. Grazie!
Mat Schaffer,

sì, è sporco e limitato, ma può essere migliorato come: In { sleep 5 && kill -9 $(ps -fe | grep "program" | grep $$ | tr -s " " | cut -d" " -f2); } & SLEEPPID=$!; bash -c "program" && kill -9 $SLEEPPID"questo modo, ucciderà solo i lavori nella shell corrente.
ton

2

C'è anche cratimeoutdi Martin Cracauer (scritto in C per sistemi Unix e 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'

"In particolare, preserva il comportamento del segnale." Bello avere questa opzione!
sistema PAUSA

1

OS X non usa ancora bash 4, né ha / usr / bin / timeout, quindi ecco una funzione che funziona su OS X senza home-brew o macport che è simile a / usr / bin / timeout (basato su Tino risposta). Convalida dei parametri, aiuto, utilizzo e supporto per altri segnali sono un esercizio per il lettore.

# 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

Nel 99% dei casi la risposta NON è implementare alcuna logica di timeout. La logica del timeout è in quasi tutte le situazioni un segnale di avvertimento rosso che qualcos'altro è sbagliato e dovrebbe invece essere risolto .

Il processo si blocca o si interrompe dopo n secondi a volte? Quindi scopri perché e correggilo invece.

Per inciso, per fare bene la soluzione di strager, devi usare wait "$ SPID" invece di fg 1, poiché negli script non hai il controllo del lavoro (e provare ad accenderlo è stupido). Inoltre, fg 1 si basa sul fatto che non è stato precedentemente avviato alcun altro lavoro nello script, il che è una pessima ipotesi da fare.


4
Con l'accesso al 100% della fonte (e la maggior parte dell'hardware, come gli switch di rete), sarei d'accordo sul fatto che probabilmente ci sono soluzioni migliori di un timeout. Ma quando un 'tlrbsf' è a codice chiuso, solo binario, a volte devi aggirare quella limitazione.
sistema PAUSA

@lhunath, "negli script non hai il controllo del lavoro (e cercare di attivarlo è stupido)" - Per favore, chiarisci qui: stackoverflow.com/questions/690266/…
sistema PAUSA

@System PAUSE: Reply stackoverflow.com/questions/690266/... è corretta, ho anche commentato su di esso.
lhunath,

29
Lhunath, quello che stai dicendo non ha senso. ci sono tonnellate di casi in cui il timeout è una buona opzione, ad esempio ogni volta che si deve passare attraverso la rete.
Nate Murray,

Un'eccezione: stai scrivendo script di test per verificare se un software già in esecuzione non ha problemi di timeout.
Peter - Ripristina Monica il

0

Mi è stato presentato un problema per preservare il contesto della shell e consentire i timeout, l'unico problema è che interromperà l'esecuzione dello script sul timeout, ma va bene con le esigenze che mi sono state presentate:

#!/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

con le uscite:

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

ovviamente suppongo che ci fosse un dir chiamato 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 Scusate ho dimenticato perché ho cambiato la linea di terminazione del processo e perché ho pensato che fosse importante condividere. Peccato che non l'ho scritto. Forse, ho scoperto che dovevo fare una pausa prima di verificare il successo del Kill -s TERM. La sceneggiatura del libro di cucina del 2008 sembra controllare lo stato del processo immediatamente dopo l'invio di SIGTERM, probabilmente portando a un errore nel tentativo di inviare SIGKILL a un processo che è morto.
Eel GhEEz

0

Il mio problema era forse un po 'diverso: avvio un comando tramite ssh su una macchina remota e voglio uccidere la shell e i figli se il comando si blocca.

Ora uso quanto segue:

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

In questo modo il comando restituisce 255 in caso di timeout o codice di ritorno del comando in caso di esito positivo

Si noti che i processi di uccisione da una sessione ssh sono gestiti in modo diverso da una shell interattiva. Ma puoi anche usare l'opzione -t per ssh per allocare uno pseudo terminale, quindi si comporta come una shell interattiva


0

Ecco una versione che non si basa sulla generazione di un processo figlio: avevo bisogno di uno script autonomo che incorporasse questa funzionalità. Fa anche un intervallo di polling frazionario, quindi puoi eseguire il polling più velocemente. il timeout sarebbe stato preferito, ma sono bloccato su un vecchio server

# 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

Un modo molto semplicistico:

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

con pkill (opzione -f ) puoi uccidere il tuo comando specifico con argomenti o specificare -n per evitare di uccidere il vecchio processo.


Ti rendi conto che questo è essenzialmente ciò che l'OP ha nel suo post e ciò che indica che non vuole, giusto? Perché attende sempre il ritardo completo del sonno.
Etan Reisner,

-1

Sulla base della risposta di @ loup ...

Se si desidera eseguire il timeout di un processo e silenziare il processo di interruzione / output pid, eseguire:

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

Ciò inserisce il processo in background in una subshell in modo da non vedere l'output del lavoro.


-3

Ho un lavoro cron che chiama uno script php e, a volte, si blocca sullo script php. Questa soluzione è stata perfetta per me.

Io uso:

scripttimeout -t 60 /script.php

1
Che cosa è scripttimeout?
Rudolfbyker,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.