In realtà, questo è ciò che timeout
è per:
TIMEOUT(1) User Commands TIMEOUT(1)
NAME
timeout - run a command with a time limit
SYNOPSIS
timeout [OPTION] DURATION COMMAND [ARG]...
timeout [OPTION]
DESCRIPTION
Start COMMAND, and kill it if still running after DURATION.
[email protected]:~$ dpkg -S /usr/bin/timeout
coreutils: /usr/bin/timeout
Ci sono (almeno) due programmi che forniscono questa funzionalità:
NOME
timelimit
— limitare efficacemente il tempo di esecuzione assoluto di un processoSINOSSI
timelimit [-pq] [-S killsig] [-s warnsig] [-T killtime] [-t warntime] command [arguments ...]
e
NOME
timeout
- eseguire un comando con un limite di tempoSINOSSI
timeout [OPTION] DURATION COMMAND [ARG]...
timeout [OPTION]
Sono impacchettati come segue:
$ dlocate `which timeout timelimit`
timelimit: /usr/bin/timelimit
coreutils: /usr/bin/timeout
Confronto:
/-----------------------------+------------+----------------\
| Feature | timelimit | timeout |
+=============================+============+================+
| time to run | -t time | first argument |
+-----------------------------+------------+----------------+
| terminate signal | -s signal | -s signal |
+-----------------------------+------------+----------------+
| grace period | -T time | -k time |
+-----------------------------+------------+----------------+
| kill signal | -S signal | (note 1) |
+-----------------------------+------------+----------------+
| propagate signals | -p | (note 2) |
\-----------------------------+------------+----------------/
Note:
timeout
utilizza sempreSIGKILL
come segnale di ultima istanza.timeout
non ha alcuna funzionalità per uscire con un segnale quando il programma figlio lo fa.
Lo stato di uscita dei due programmi differisce, ma è difficile riassumerlo in modo chiaro, quindi ti suggerisco di consultare tu stesso le pagine di manuale per questo.
Come timeout
è installato su più sistemi per impostazione predefinita (coreutils
è un pacchetto standard in molte distribuzioni), ti suggerisco di usarlo a meno che tu non abbia bisogno delle funzionalità extra fornite da timelimit
.
Puro bash
integrato, senza coreutils
Ho scoperto che questa soluzione funziona in bash
basandosi su un integrato comando senza chiamare un eseguibile esterno. Funziona su sistemi dove eventualmente non sono stati nemmeno installati i coreutils
YourCommand & read -t 300 ; kill $! # 1st version
YourCommand & read -t 300 || kill $! # 2nd version
Spiegazioni :come al solito quando invii un comando in background con &
, il suo PID è memorizzato nella variabile interna $!
(presente nella versione moderna di dash
, csh
, bash
, tcsh
, zsh
...).
Ciò che fa veramente la differenza tra le shell è la presenza del integrato comando read
e dell'opzione -t
.Nella prima versione, se l'utente non completa una riga di input prima del numero di secondi specificato, l'istruzione verrà terminata e verrà generato un codice di ritorno di errore.
La seconda versione funziona come la prima ma puoi annullare il timeout di uccisione semplicemente premendo invio .
Infatti l'operatore or ||
esegue il kill
istruzione solo se read
il comando termina con un codice di ritorno diverso da zero, come quando il timeout è scaduto. Se premi invio prima di quel momento, restituirà 0 e non interromperà il comando precedente.
Soluzioni Coreutils
Quando coreutils sono presenti sul tuo sistema e non hai bisogno di risparmiare tempo e risorse per chiamare un programma esterno, timeout
e sleep
e sono entrambi modi perfetti per raggiungere il tuo obiettivo.
timeout
L'uso di timeout
è semplice.
Eventualmente puoi considerare di utilizzare anche il -k
opzione per inviare un ulteriore kill signal se il primo fallisce.
timeout 5m YourCommand # 3rd version
sleep
Con sleep
puoi usare la tua fantasia o prendere qualche ispirazione. Nota che puoi lasciare il comando in background o in primo piano (ad es. top
di solito deve essere in primo piano).
YourCommand & sleep 5m; kill $! # 4th Background
YourCommand & pid=$! ; (sleep 5m; kill $pid;) & # 5th Background
bash -c '(sleep 5m; kill $$) & exec YourCommand' # 6th Foreground
(cmdpid=$BASHPID; (sleep 5m; kill $cmdpid) & exec YourCommand) # 7th Foreground
Spiegazioni
Ovviamente in ogni versione puoi inviare il segnale di kill di cui hai bisogno, da quello predefinito a quello estremo kill -9
, da utilizzare solo quando realmente necessario.
Riferimenti
- [1] Le Coreutils
- [2] La guida per principianti di Bash
- [3] Domande frequenti su Bash