2015-06-19 11 views
6

In uno script rubino, ci sono various ways chiamare comandi di sistema/righe di comandoCome far fallire lo script Ruby quando il comando shelled-out restituisce un codice di uscita diverso da zero?

  1. backticks: `command arg1 arg2`
  2. forma delimitato, ad esempio %x(command arg1 arg2) (altri delimitatori disponibili)
  3. Kernel#system metodo: system('command arg1 arg2')
  4. Kernel#exec metodo: exec('command arg1 arg2')

Se voglio lo script di Ruby a fallire (con un'eccezione) quando un comando chiamato fallisce (con un non-zero codice di uscita) posso o controllare il codice di uscita nella variabile speciale $? per i primi due varianti:

`command arg1 arg2` 
fail unless $? == 0 

o

%x,command arg1 arg2, 
fail unless $? == 0 

Se sto bene con lo standard output del comando andando a standard output dello script di Ruby (e sono), posso usare la variante 3 e controllare il suo valore di ritorno:

unless system('command arg1 arg2') 
    fail 
end 

Se io non mi interessa la possibilità di salvare l'eccezione né il comportamento di stampa stacktrace di eccezioni non ridotte, posso ovviamente usare exit(1) o nelle prime due varianti exit($?) al posto di fail.

Se ulteriormente l'esecuzione del comando è l'ultima cosa che lo script di Ruby dovrebbe fare, anche quando il comando ha esito positivo (codice di uscita 0), posso usare la quarta variante:

exec('command arg1 arg2') 

Questo sostituirà la Processo di Ruby con il nuovo processo creato invocando il comando, ma l'effetto per il chiamante dello script Ruby sarà lo stesso: Verrà visualizzato un codice di uscita diverso da zero esattamente se il comando chiamato ha causato un codice di uscita diverso da zero.

Mi piace molto la concisione della quarta variante, ma se eseguire il comando non è l'ultima cosa da fare in caso di esito positivo, purtroppo non lo uso. Le invocazioni condizionali fail o exit delle altre varianti appaiono molto impure in confronto e in un caso precedente il mio non violano il singolo livello di astrazione e principi di responsabilità singola.

Potrei ovviamente scrivere facilmente una funzione wrapper per uno dei primi tre approcci per rendere il loro uso un aspetto altrettanto conciso, ma poiché sembra un modus operandi così fondamentale, Mi chiedevo se Ruby abbia già qualcosa del genere costruito in ... sia una funzione di utilità che potrei usare al posto di un wrapper o un meccanismo che modifica il comportamento di uno o più metodi di chiamata di comando per causare un errore o un'uscita diversa da zero quando un comando fallito, analogo a e option to set -eoption to set -e.

risposta

4

Per quanto ne so non c'è modo incorporato per fare questo, ma si può quasi ottenere il comportamento desiderato con un po 'di metaprogrammazione magia

def set_exit enable 
    if enable 
    define_method :system do |*args| 
     Kernel.system *args 
     exit $?.exitstatus unless $?.success? 
    end 
    else 
    define_method :system, Kernel.instance_method(:system) 
    end 
end 

set_exit true 
# ... 
# any failed system calls here will cause your script to exit 
# ... 
set_exit false 
# now system is back to normal 

Questo funziona ridefinendo system per Object, mentre utilizzare esplicitamente Kernel.system quando è necessario il comportamento predefinito.

+1

Bello. Poiché [i backquote usano 'Kernel # \' '] (http://ruby-doc.com/docs/ProgrammingRuby/html/tut_expressions.html#UB), immagino che questo approccio possa funzionare anche per loro. –

+0

Wow, non sapevo che fosse in realtà un metodo! Sì, sembra funzionare bene se si sostituisce ': \' 'per': system' – Max

Problemi correlati