2015-01-06 30 views
12

ho usato un semplice preambolo bash come questa nel mio script:Utilizzare set set -e/+ e in bash con funzioni

#!/bin/bash 
set -e 

In concomitanza con la modularità/usando le funzioni di questo mi ha morso oggi.

Quindi, dire che ho una funzione da qualche parte come

foo() { 
    #edit: some error happens that make me want to exit the function and signal that to the caller 
    return 2 
} 

Idealmente mi piacerebbe essere in grado di utilizzare più file di piccole dimensioni, includo le loro funzioni in altri file e quindi chiamare queste funzioni come

set +e 
foo 
rc=$? 
set -e 

. Questo funziona esattamente per due livelli di routine. Ma se foo chiama anche subroutine come questa, l'ultima impostazione prima del ritorno sarà set -e, che farà uscire lo script al ritorno - Non posso sovrascriverlo nella funzione di chiamata. Allora, che cosa ho dovuto fare è

foo() { 
    #calling bar() in a shielded way like above 
    #..  

    set +e 
    return 2 
} 

che trovo molto controintuitivo (e anche non quello che voglio - e se in alcuni contesti vorrei utilizzare la funzione senza schermatura contro i guasti, mentre in altri contesti Voglio gestire la pulizia?) Qual è il modo migliore per gestire questo? Btw. Lo sto facendo su OSX, non ho testato se questo comportamento è diverso su Linux.

+0

attendere, potresti espandere? Devo aggiungere questo nel chiamante? Cosa fa il colon? –

+0

Potresti spiegare come sto tornando? Come intendo allora segnalare l'errore dall'interno di una funzione? (scusate se non sono stato abbastanza chiaro - il 'return 2' è fatto solo in una condizione di errore –

+1

Non lo siete, ma pensavo che lo foste. Il mio male, mi dispiace – Carpetsmoker

risposta

13

Le funzioni di shell non hanno realmente "valori di ritorno", solo codici di uscita.

Si potrebbe aggiungere && : al chiamante, questo rende il comando "testata", e non saranno uscirne:

foo() { 
    echo 'x' 
    return 42 
} 

out=$(foo && :) 
echo $out 

Il : è il comando "null" (vale a dire che non fa. nulla). In questo caso non viene nemmeno eseguito, poiché viene eseguito solo se foo restituisce 0 (che non è).

This uscite:

x 

è senza dubbio un po 'brutto, ma poi di nuovo, tutti shell scripting è probabilmente un po' brutto ;-)

Citando sh(1) da FreeBSD, che spiega meglio di pagina man di bash:

-e errexit 
     Exit immediately if any untested command fails in non-interactive 
     mode. The exit status of a command is considered to be explicitly 
     tested if the command is part of the list used to control an if, 
     elif, while, or until; if the command is the left hand operand of 
     an “&&” or “||” operator; or if the command is a pipeline preceded 
     by the ! operator. If a shell function is executed and its exit 
     status is explicitly tested, all commands of the function are con‐ 
     sidered to be tested as well. 
+0

(maledetto, niente nuova riga nei commenti;)). Grazie uomo. Ora vedo. Quindi, d'ora in poi, se voglio eseguire una funzione in modo "testato", lo farò set + e foo &&: rc = $? set -e –

+1

@ MichelMüller Non è necessario fare nulla con 'set'; usi semplicemente 'set -e' una volta per abilitare questo nel tuo script, e poi per" aggirarlo ", per così dire, usa' &&: '. – Carpetsmoker

+0

giusto, ha senso. Grazie. –