web-dev-qa-db-fra.com

Script Bash: corriger les erreurs dans un bloc d'instructions

J'ai un grand ensemble de règles iptables que je gère avec mon propre script bash. La plupart des commandes du script sont des commandes iptables simples, à une seule déclaration. J'essaie d'améliorer le script en ajoutant une sortie de succès/échec lors de son exécution.

J'ai le script divisé en différentes sections. Un exemple serait la section de la chaîne FORWARD, où toutes les règles sont appliquées à la chaîne FORWARD. Au début de la section, je signale que le script a commencé à appliquer les règles FORWARD et, à la fin, je souhaite indiquer si toutes les règles ont été appliquées avec succès ou si aucune d'entre elles n'a fonctionné. Voici l'idée de base:

#Start FORWARD section
echo -ne "Applying FORWARD rules..."

#rule 1
/sbin/iptables -A FOWRARD...

#rule 2
/sbin/iptables -A FORWARD...

echo -ne "\t\t\t[OK]\n"

Ce que je veux faire, c'est récupérer toutes les sorties ou erreurs pouvant découler de chaque commande iptables et les stocker dans un tableau ou autre. Puis, à la fin du bloc, utilisez une instruction if pour évaluer le tableau et voir s’il ya des erreurs. Sinon, indiquez le statut [OK], le cas échéant, indiquez le statut [FAILED] et affichez l'erreur associée.

Est-il possible de faire cela pour tout le bloc de règles sans envelopper chaque règle iptables dans un if [$? ! = 0] expression?

4
Miles Stevenson

Vous pouvez utiliser la commande intégrée trap Shell pour qu'une fonction de gestionnaire soit appelée si une commande a un statut de sortie autre que zéro. Vous pouvez transmettre les informations nécessaires, telles que le numéro de ligne et l'état de sortie, à votre fonction de gestion des erreurs.

Exemple:

#!/bin/bash

handle_error() {
    echo "FAILED: line $1, exit code $2"
    exit 1
}

trap 'handle_error $LINENO $?' ERR 

# your commands here
# ...

echo "OK"
11
Jukka Matilainen

Le script ci-dessous définira la fonction recordfailure qui doit être ajoutée aux commandes, comme indiqué dans l'exemple suivant la définition de la fonction. Si la commande renvoie une valeur autre que zéro, le flux d'erreur standard est consigné. Enfin, à la fin, le journal des erreurs est vérifié et [OK] ou [FAIL] est imprimé en conséquence.

#!/bin/bash

# Redirect file descriptor #3 to standard output (used in recordfailure)
exec 3>&1

# create an array for holding failures
declare -a failures

# recordfailure command arg1 arg2 ... argN
recordfailure() {
    local error retval
    # Run the command and store error messages (output to the standard error
    # stream in $error, but send regular output to file descriptor 3 which
    # redirects to standard output
    error="$("$@" 2>&1 >&3)"
    retval=$?
    # if the command failed (returned a non-zero exit code)
    if [ $retval -gt 0 ]; then
        if [ -z "$error" ]; then
            # create an error message if there was none
            error="Command failed with exit code $retval"
        fi
        # uncomment if you want the command in the error message
        #error="Command $* failed: $error"

        # append the error to $failures, ${#failures[@]} is the length of
        # the array and since array start at index 0, a new item is created
        failures[${#failures[@]}]="$error"
        # uncomment if you want to show the error immediately
        #echo "$error"
    fi
}
recordfailure iptables -A FORWARD ...
recordfailure iptables -A FORWARD ...
# if the length of the failures array equals 0 (no items) everything is OK
if [ ${#failures[@]} -eq 0 ]; then
    echo "[OK]"
else
    echo "[FAIL]"
    # list every error
    for failure in "${failures[@]}"; do
        # optionally color it, format it or whatever you want to do with it
        echo "error: $failure"
    done
fi

Si vous ne souhaitez pas afficher de sortie standard, supprimez exec 3>&1 et remplacez >&3 par >/dev/null.

0
Lekensteyn