2013-07-24 16 views
26

Ho un piccolo snippet di uno script di shell che ha il potenziale di generare molti errori. Ho lo script attualmente impostato su Globally Stop su tutti gli errori. Comunque mi piacerebbe che questa piccola sotto-sezione fosse leggermente diversa.Ignorare errori specifici su Shell Script

Ecco il frammento:

recover database using backup controlfile until cancel || true; 
auto 

mi aspetto questo per poi lanciare un errore "File non trovato". Tuttavia vorrei continuare a eseguire questo errore. Per qualsiasi altro errore vorrei che lo script si fermasse.

Quale sarebbe il metodo migliore per raggiungere questo obiettivo?

Bash versione 3.00.16

+2

Fa [questo] (http://stackoverflow.com/questions/64786/error-handling-in-bash) aiuto? E, benvenuto in SO! :) –

+0

Questo aiuta a migliorare la segnalazione degli errori, ma non include nulla per gestire errori diversi in un altro maniero. Sto essenzialmente cercando di imitare il try {} catch {} da C# – Stunt

risposta

60

Al fine di evitare che bash di ignorare l'errore per comandi specifici si può dire:

some-arbitrary-command || true 

Ciò renderebbe lo script continuare. Per esempio, se avete il seguente script:

$ cat foo 
set -e 
echo 1 
some-arbitrary-command || true 
echo 2 

esecuzione che sarebbe tornato:

$ bash foo 
1 
z: line 3: some-arbitrary-command: command not found 
2 

In assenza di || true nella linea di comando, che sarebbe potuto produrre:

$ bash foo 
1 
z: line 3: some-arbitrary-command: command not found 

Citazione da manual:

la shell non esce se il comando che fallisce è parte della lista comando immediatamente dopo un while o until parola, parte prova in un if dichiarazione, parte di qualsiasi comando eseguito in un elenco && o || eccetto il comando che segue l'ultimo && o ||, qualsiasi comando in una pipeline ma l'ultimo, o se lo stato di ritorno del comando è invertito con !. Una trappola su ERR, se impostata, viene eseguita prima delle uscite della shell .

EDIT: Al fine di modificare il comportamento in modo tale che nella esecuzione dovrebbe continuare solo se esecuzione some-arbitrary-command restituito file not found come parte dell 'errore, si può dire:

[[ $(some-arbitrary-command 2>&1) =~ "file not found" ]] 

A titolo di esempio, eseguire il seguente (nessun file chiamato MissingFile.txt esiste):

$ cat foo 
#!/bin/bash 
set -u 
set -e 
foo() { 
    rm MissingFile.txt 
} 
echo 1 
[[ $(foo 2>&1) =~ "No such file" ]] 
echo 2 
$(foo) 
echo 3 

Questo produce il seguente output:

$ bash foo 
1 
2 
rm: cannot remove `MissingFile.txt': No such file or directory 

Nota che echo 2 fu eseguito, ma non era echo 3.

+0

Si tratta più di un sostituto per il mio utilizzo "set + e e set -e"? Non sono sicuro di capire come questo gestisca errori variabili. – Stunt

+0

@Stunt Questa non è una sostituzione. Implica solo che se tu avessi 'set -e' all'inizio dello script, non devi dire' set + e' per ignorare gli errori. Dicendo 'comando || true! sarebbe sufficiente – devnull

+0

Questo è utile per pulire il mio codice (il set + e set -e può diventare abbastanza disordinato!) Tuttavia sta ancora gestendo gli errori su una base più generale. Per questa domanda mi piacerebbe controllare l'errore e quindi continuare o uscire in base a quale errore viene generato. (Non vedo come votare il tuo commento come utile!) – Stunt

17

Usa:

command || : 

: è un bash integrato che restituisce sempre il successo. E, come discusso sopra, || cortocircuiti quindi l'RHS viene eseguito solo se l'LHS fallisce (restituisce un valore diverso da zero).

I suggerimenti sopra riportati per utilizzare "true" funzioneranno anche, ma sono inefficienti poiché "true" è un programma esterno.

+2

True è solo un programma esterno se si esegue '/ bin/true', dato che' true' da solo è un built-in di shell di bash, proprio come echo e test, che esiste anche come programmi esterni ma sono anche built-in in bash e se non si fornisce un percorso completo, verranno utilizzati i built-in. – Mecki