2011-10-21 2 views
21

Ho uno script che tenta di stabilire una connessione DB utilizzando un altro programma e il timeout (2.5min) del programma è troppo lungo. Voglio aggiungere questa funzionalità allo script.Processo di uccisione dopo un determinato intervallo di tempo?

Se per la connessione occorrono più di 5 secondi, interrompere il processo
Altrimenti chiudere il processo di sospensione/interruzione.

Il problema che sto verificando è come i report di bash quando un processo viene ucciso, perché i processi si trovano nella stessa shell solo sullo sfondo. C'è un modo migliore per farlo o come posso silenziare la shell per i comandi kill?

DB_CONNECTION_PROGRAM > $CONNECTFILE & 
pid=$! 
(sleep 5; kill $pid) & 
sleep_pid=$! 
wait $pid 

# If the DB failed to connect after 5 seconds and was killed 
status=$? #Kill returns 128+n (fatal error) 
if [ $status -gt 128 ]; then 
    no_connection="ERROR: Timeout while trying to connect to $dbserver" 
else # If it connected kill the sleep and any errors collect 
    kill $sleep_pid 
    no_connection=`sed -n '/^ERROR:/,$p' $CONNECTFILE` 
fi 
+0

Ho trovato i vecchi script Bash e sono molto simili ai tuoi.Stavo usando il bit-bucket (*/dev/null *) e * kill -9 * molto più liberamente e non penso ci fosse molto problema con * kill * che mostrava messaggi indesiderati: stranamente quel codice è ancora in uso, anni dopo, nel mio prompt dei comandi! (se ci fossero problemi di visualizzazione lo vedrei nel mio prompt, credo). È da tanto che non l'ho toccato, ma sembra (ancora) funzionare bene. – TacticalCoder

+0

Ho ricopiato la carne del mio script di shell Bash come risposta. Spero che sia d'aiuto. – TacticalCoder

+0

Dai un'occhiata a questo: http://redflo.de/tiki-index.php?page=Bash+script+with+timeout+function –

risposta

9

Non so se è identico ma ho fatto risolvere un problema simile a pochi anni fa. Comunque sono un programmatore, non un sysadmin simile a Unix quindi prendi il seguente con un pizzico di sale perché il mio Bash-fu potrebbe non essere così forte ...

Fondamentalmente ho fatto forchetta, forcella e forcella:)

out of memory Dopo aver fondato indietro il mio vecchio codice (che incredibilmente ancora utilizzare tutti i giorni), perché la mia memoria non era abbastanza buono, in Bash ha funzionato un po 'come questo:

commandThatMayHang.sh 2 > /dev/null 2>&1 & (notice that last '&', we're forking) 
MAYBE_HUNG_PID=$! 
sleepAndMaybeKill.sh $MAYBE_HUNG_PID 2 > /dev/null 2>&1 & (we're forking again) 
SLEEP_AND_MAYBE_KILL_PID=$! 
wait $MAYBE_HUNG_PID > /dev/null 2>&1 
if [ $? -eq 0 ] 
    # commandThatMayHand.sh did not hang, fine, no need to monitor it anymore 
    kill -9 $SLEEP_AND_MAYBE_KILL 2> /dev/null 2>&1 
fi 

dove sleepAndMaybeKill .sh dorme il tempo che vuoi e poi uccide commandThatMayHand.sh.

Quindi, in pratica i due scenari sono:

  1. vostre uscite di comando fine (prima che i 5 secondi timeout o qualsiasi altra cosa) e così il aspettare fermata non appena il comando termina bene (e uccide il " killer" perché non è più necessaria

  2. il comando si blocca, l'assassino finisce per uccidere il comando

In ogni caso, si è certi di avere successo non appena il comando è stato eseguito o di fallire dopo il timeout.

0

Vuoi dire che non vuoi il messaggio di errore stampata se il processo non è ancora in esecuzione? Quindi puoi semplicemente reindirizzare lo stderr: kill $pid 2>/dev/null.

Si potrebbe anche verificare se il processo è ancora in esecuzione:

if ps -p $pid >/dev/null; then kill $pid; fi 
+0

Voglio farlo funzionare e se ci vuole più tempo, allora 5 secondi per connettersi (cambia stato) Voglio il PID ucciso. Altrimenti, voglio interrompere il sonno e uccidere il PID anche correndo e uccidendo il PID da quando ha avuto successo. – LF4

87

C'è una GNU utility coreutils chiamato timeout: http://www.gnu.org/s/coreutils/manual/html_node/timeout-invocation.html

Se lo avete sulla vostra piattaforma, si poteva fare:

timeout 5 CONNECT_TO_DB 
if [ $? -eq 124 ]; then 
    # Timeout occurred 
else 
    # No hang 
fi 
+5

Su Mac: brew install coreutils. Ora il comando è gtimeout. –

+1

Questa dovrebbe essere la risposta accettata. –