2014-05-22 21 views
5

Bawiłem się przy użyciu trap wewnątrz funkcji z powodu this question, i wpadłem na to pytanie wtórne. Biorąc pod uwagę następujący kod:Gdzie status wyjścia następuje po pułapce/zwrocie?

d() { 
    trap 'return' ERR 
    false 
    echo hi 
} 

Jeśli biegnę d The trap powoduje, że powłoka powrotu z funkcji drukowania bez 'cześć'. Jak na razie dobrze. Ale jeśli uruchomię go po raz drugi, dostaję wiadomość od powłoki:

-bash powrotu: Tylko Ty `zwrot” z funkcją lub pochodzących skrypt

Początkowo Przypuszczałem oznaczało to, że sygnał ERR wystąpił dwukrotnie: raz, gdy false podał niezerowy status wyjścia (w funkcji) i ponownie, gdy sama funkcja powróciła z niezerowym stanem wyjścia (poza funkcją). Ale to hipoteza nie trzyma się na tym teście:

e() { 
    trap 'echo +;return' ERR 
    false 
    echo hi 
} 

Gdybym uruchomić powyżej, bez względu na to, jak często go uruchomić, już nie dostać mogą tylko return z funkcji lub są pobierane skrypt ostrzeżenie z bash. Dlaczego powłoka traktuje polecenie złożone innym niż proste polecenie w argumencie trap?

Moim celem było utrzymanie aktualnego stanu wyjścia polecenia, który spowodował funkcja, aby wyjść, ale myślę, że cokolwiek jest przyczyną powyższej zachowanie również sprawia uchwycenie stanu wyjścia złożona:

f() { 
    trap ' 
     local s=$? 
     echo $s 
     return $s' ERR 
    false 
    echo hi 
} 

bash> f; echo $? 
1 
0 

Wat? Czy ktoś może wyjaśnić, dlaczego $s rozwija się tutaj do dwóch różnych wartości, a jeśli okaże się, że jest to ta sama przyczyna, to powyższe rozróżnienie między return a echo +; return?

+1

Istnieje kilka zaskakujących problemów dotyczących zakresu. Twoje pułapki nie są specyficzne dla funkcji, ale globalne. Zauważ, że jeśli utworzysz funkcję e(), a następnie wpiszesz nieprawidłowe polecenie, takie jak "ggg", trafi ono w twoją pułapkę i pojawi się komunikat o błędzie. Śledzenie z opcją -vx pokazuje również, że w twoim pierwszym przykładzie "powracasz" dwa razy, po tym, jak został on raz uruchomiony. –

+0

Przekazywanie statusu wyjścia komendy 'trap'ped może być trudne, ponieważ' man bash' stwierdza: "Status powrotu [z pułapki] jest fałszywy, jeśli jakikolwiek sigspec jest nieprawidłowy, w przeciwnym razie pułapka zwróci true." –

Odpowiedz

3

Twój pierwszy wniosek był słuszny: sygnał ERR zdarzył się dwa razy.

Podczas pierwszego wykonywania "d", definiujesz pułapkę na całym świecie. Wpływa to na kolejne polecenia (nie ma to wpływu na bieżące wywołanie d). Podczas drugiego wykonania 'd', ponownie definiujesz pułapkę (niezbyt przydatną), wywołanie "false" kończy się niepowodzeniem, więc wykonujemy procedurę zdefiniowaną przez pułapkę. Następnie wracamy do powłoki nadrzędnej, w której również występuje błąd "d", więc ponownie wykonujemy pułapkę.

Tylko uwaga. ERR można podawać jako "sigspec argument, ale ERR nie jest sygnałem ;-) Z instrukcji bash:

If a sigspec is ERR, the command arg is executed whenever a sim‐ 
ple command has a non-zero exit status, subject to the following 
conditions. [...] 
These are the same conditions obeyed by the errexit option. 

Dzięki funkcji„e”, przewodnik ERR wykonuje„echo”polecenie powiedzie . Dlatego funkcja "e" nie zawodzi, dlatego obsługa błędów ERR nie jest w tym przypadku wywoływana dwukrotnie.

Jeśli spróbujesz "e; echo $?" będziesz czytać "0".

Potem spróbowałem twojej funkcji "f". Obserwowałem to samo zachowanie (i byłem zaskoczony). Przyczyną jest nieprawidłowe rozszerzenie "$ s". Jeśli spróbujesz kodować wartość, powinieneś zauważyć, że argument podany w instrukcji "return" jest ignorowany, gdy jest wykonywany przez program obsługi pułapek.

Nie wiem, czy to normalne zachowanie, czy jest to błąd BASH ...A może sztuczka, aby uniknąć nieskończonej pętli w tłumaczu :-)

Przy okazji, to nie jest dobre wykorzystanie pułapki w mojej opinii. Możemy uniknąć skutków ubocznych pułapki, tworząc pod-powłokę. W tym przypadku unikamy błędu w powłoce rodzicielskiej i zachowujemy kod funkcji wewnętrznej:

g() (
    trap 'return' ERR 
    false 
    echo hi 
) 
+1

BTW, 'g() (...)' - no '{}' s w ogóle - jest gorszym sposobem, aby to napisać. –

+0

Zaktualizowałem moją odpowiedź. Dzięki – mcoolive