2016-12-27 4 views
4

Es gibt Empfehlungen zu den folgenden Optionen verwenden Bash machen scheitern schnell:Bash scheitern schnell Funktionen

set -o errexit 
set -o nounset 
set -o pipefail 

jedoch Diese Optionen funktionieren nicht für Bash-Funktionen erwartet, über || geleitet.

z. in Skript

#!/bin/bash 

set -o errexit 
set -o nounset 
set -o pipefail 

my_function() { 
    test -z "$1" 
    echo "this SHOULD NOT be printed" 
} 

my_function 1 || echo "???" # 1 

my_function 1 # 2 

echo "this will not be printed" 

Linie # 2 wird das Skript verursacht mit Code 1 ohne Ausgang zu beenden. Das ist, was ich erwarte.

Zeile # 1 verwirrt mich eigentlich: my_function wird erfolgreich abgeschlossen, Drucken "das sollte nicht gedruckt werden" und Rückgabecode 0, also die "???" wird nicht gedruckt.

Wie kann ich Bash my_function on line # 1 Bash Prozess # 2 machen?

+0

Nur aus Neugier, wo haben Sie diese Dinge empfohlen? –

Antwort

2

an der Bash-Handbuch Sehen, ist hier, was für den trap Befehl ist, sagt:

trap [-lp] [arg] [sigspec …]

Wenn ein sigspec ist ERR, wird der Befehl arg ausgeführt, wenn eine Pipeline (die aus bestehen ein einzelner einfacher Befehl), eine Liste oder ein zusammengesetzter Befehl gibt einen Nicht-Null-Exit-Status zurück, der den folgenden Bedingungen unterliegt: . Der ERR-Trap wird nicht ausgeführt, wenn der fehlgeschlagene Befehl Teil der Befehlsliste unmittelbar nach einem Schlüsselwort bis oder while ist, Teil des Tests, der den if- oder elif-reservierten Wörtern folgt, Teil eines oder & oder | | Liste mit Ausnahme des Befehls nach final & & oder ||, ein beliebiger Befehl in einer Pipeline aber der letzte, oder wenn der Rückkehrstatus des Befehls mit Hilfe von!. Dies sind die gleichen Bedingungen, die von der Option errexit (-e) erfüllt werden.

Schauen Sie sich den letzten Satz besonders an. Das erklärt es!

6

Es gibt auch bessere Empfehlungen not to use set -e/errexit:

Klar wir nicht abbrechen wollen, wenn die bedingte (in if [ -d /foo ]; then), ungleich Null zurückgibt. [...] Die Implementierer beschlossen, eine Reihe spezieller Regeln zu erstellen, wie "Befehle, die Teil eines if-Tests sind, sind immun", oder "Befehle in einer Pipeline, außer der letzten, sind immun".

Diese Regeln sind extrem verworren, und es gelingt ihnen immer noch nicht einmal, einige sehr einfache Fälle zu erfassen. Schlimmer noch, die Regeln ändern sich von einer Bash-Version zur anderen, da Bash versucht, die extrem schlüpfrige POSIX-Definition dieses "Features" zu verfolgen. Wenn eine Subshell beteiligt ist, wird es noch schlimmer - das Verhalten ändert sich je nachdem, ob Bash im POSIX-Modus aufgerufen wird.

Wenn das Skript auf einer Nicht-Null-Rückkehr zu stoppen, würde foo || bar auch nutzlos sein, weil bar würde nie (würde stattdessen verläßt das Skript) auszuführen.Daher ist eine dieser verschachtelten Regeln, dass Nicht-Null-Returns in Befehlen auf der linken Seite von && oder || das Skript nicht zum Beenden führen. Dies ist der Effekt, den Sie sehen.

Es gibt keine Möglichkeit, set -e ordnungsgemäß zu arbeiten, und es gibt keinen automatischen Ersatz. Sie können nicht so arbeiten, wie Sie wollen, ohne manuelle Fehlerbehandlung zu schreiben.