web-dev-qa-db-fra.com

Existe-t-il un moyen d'écrire une fonction bash qui abandonne l'exécution entière, quel que soit son nom?

J'utilisais l'instruction "exit 1" dans mes fonctions bash pour terminer l'ensemble du script et cela a bien fonctionné:

function func()
{
   echo "Goodbye"
   exit 1
}
echo "Function call will abort"
func
echo "This will never be printed"

Mais je me suis alors rendu compte qu'il ne faisait pas le travail quand on l'appelait comme:

res=$(func)

Je comprends que j'ai créé un sous-shell et que la "sortie 1" abandonne ce sous-shell et non le principal ....

Mais existe-t-il un moyen d'écrire une fonction qui abandonne l'exécution entière, peu importe comment elle est appelée? J'ai juste besoin d'obtenir la valeur de retour réelle (reprise par la fonction).

68
LiMar

Ce que vous pourriez faire, c'est enregistrer le Shell de niveau supérieur pour que le signal TERM se termine, puis envoyer un TERM au Shell de niveau supérieur:

#!/bin/bash
trap "exit 1" TERM
export TOP_PID=$$

function func()
{
   echo "Goodbye"
   kill -s TERM $TOP_PID
}

echo "Function call will abort"
echo $(func)
echo "This will never be printed"

Ainsi, votre fonction envoie un signal TERM au shell de niveau supérieur, qui est intercepté et géré à l'aide de la commande fournie, dans ce cas, "exit 1".

79
FatalError

Vous pouvez utiliser set -e qui se ferme si une commande se termine avec un état différent de zéro :

set -e 
func
set +e

Ou saisissez la valeur de retour:

(func) || exit $?
34
brice

Mais existe-t-il un moyen d'écrire une fonction qui abandonne l'exécution entière, quel que soit son nom?

Non.

J'ai juste besoin d'obtenir la valeur de retour réelle (reprise par la fonction).

Vous pouvez

res=$(func)
echo $?
1
Luca

Un processus enfant ne peut pas forcer le processus parent à se fermer implicitement. Vous devez utiliser une sorte de mécanisme de signalisation. Les options peuvent inclure une valeur de retour spéciale ou envoyer un signal avec kill, quelque chose comme

function child() {
    local parent_pid="$1"
    local other="$2"
    ...
    if [[ $failed ]]; then
        kill -QUIT "$parent_pid"
    fi
}
0
Daenyth

Je suppose que c'est mieux

#!/bin/bash
set -e
trap "exit 1" ERR

myfunc() {
     set -x # OPTIONAL TO SHOW ERROR
     echo "Exit with failure"
     set +x # OPTIONAL
     exit 1
}
echo "BEFORE..."
myvar="$(myfunc)"
echo "AFTER..But not shown"
0
AmazingAlex