Bash ignorant l'erreur pour une commande particulière

444

J'utilise les options suivantes

set -o pipefail
set -e

Dans le script bash pour arrêter l'exécution en cas d'erreur. J'ai environ 100 lignes de script en cours d'exécution et je ne veux pas vérifier le code retour de chaque ligne du script.

Mais pour une commande particulière, je veux ignorer l'erreur. Comment puis je faire ça?

Vivek Goel
la source

Réponses:

757

La solution:

particular_script || true

Exemple:

$ cat /tmp/1.sh
particular_script()
{
    false
}

set -e

echo one
particular_script || true
echo two
particular_script
echo three

$ bash /tmp/1.sh
one
two

three ne sera jamais imprimé.

De plus, je veux ajouter que lorsqu'il pipefailest activé, il suffit au shell de penser que le tuyau entier a un code de sortie non nul lorsque l'une des commandes du tuyau a un code de sortie non nul (avec pipefaildésactivé, il doit être le dernier) .

$ set -o pipefail
$ false | true ; echo $?
1
$ set +o pipefail
$ false | true ; echo $?
0
Igor Chubin
la source
15
+1. Comme l' explique le Manuel de référence de Bash , "Le shell ne se ferme pas" lorsque l' -eattribut est défini "si la commande qui échoue fait partie de la liste de commandes immédiatement après un mot clé whileor until, une partie du test dans une ifinstruction, une partie de toute commande exécutée dans une liste &&ou ||à l'exception de la commande suivant la dernière &&ou ||, toute commande dans un pipeline mais la dernière, ou si le statut de retour de la commande est inversé avec !".
ruakh
@IgorChubin Je ne sais pas pourquoi mais cela ne fonctionne pas output = le (ldd $2/bin/* || true) | grep "not found" | wc -lscript se termine après cette ligne en cas d'échec de retour ldd
Vivek Goel
1
(ldd $2/bin/* || true) | grep "not found" | wc -l || true
Igor Chubin
1
à cause de set -o pipefail. lorsqu'il grepne trouve rien, il renvoie un code de sortie non nul et il suffit au shell de penser que le tube entier a un code de sortie non nul.
Igor Chubin
3
Si vous souhaitez conserver la valeur de retour (sans quitter), essayez mycommand && true. Cela vous permet de vérifier le code retour dans les étapes suivantes et de le gérer par programme.
Ed Ost
179

Ajoutez juste || trueaprès la commande où vous voulez ignorer l'erreur.

Lars Kotthoff
la source
11
Je pense qu'il est important d'ajouter ceci: cette méthode permettra au code de réponse et au message d'erreur de persister, tandis que le "!" La méthode décrite ci-dessous changera le code de réponse et ne générera donc pas l'erreur. Ceci est important lors de l'utilisation set -eet de la tentative de capture d'un message d'erreur: par exempleset -e; TEST=$(foo 2>&1 || true); echo $TEST
Spanky
87

Ne vous arrêtez pas et enregistrez également le statut de sortie

Juste au cas où si vous souhaitez que votre script ne s'arrête pas si une commande particulière échoue et que vous souhaitez également enregistrer le code d'erreur de la commande ayant échoué:

set -e
EXIT_CODE=0
command || EXIT_CODE=$?
echo $EXIT_CODE
Arslan Qadeer
la source
2
C'est exactement ce dont j'avais besoin
sarink
ne fonctionne pas pour moi pour une raison quelconque ... eh bien
Jeef
EXIT_CODE n'est pas défini sur zéro lorsque la commande renvoie 0. Les codes de sortie non nuls sont cependant capturés. Une idée pourquoi?
Ankita13
@ Ankita13 Parce que s'il était nul, le premier commanda réussi et il faut exécuter ce qui suit ||. le lire comme: en cas d' commandéchec, faites EXIT_CODE=$?. Vous pourriez probablement faire command || echo "$?"ou utiliser "trap" pour un débogage plus détaillé. Voir ceci -> stackoverflow.com/a/6110446/10737630
tinnick
63

Plus concis:

! particular_script

D'après la spécification POSIX concernant set -e(le mien est souligné):

Lorsque cette option est activée, si une commande simple échoue pour l'une des raisons répertoriées dans Conséquences des erreurs shell ou renvoie une valeur d'état de sortie> 0, et ne fait pas partie de la liste composée après un certain temps, jusqu'à ce que, ou si mot-clé if, et ne fait pas partie d'une liste ET ou OU et n'est pas un pipeline précédé du! mot réservé , le shell doit immédiatement sortir.

Lily Finley
la source
16
Cela inverse simplement le code de sortie d'une commande, donc la commande qui s'est terminée avec succès retournera 1 au lieu de 0 et échouera le script avec -e.
Marboni
17
Je crois comprendre que !cela empêchera l'obus de sortir quoi qu'il arrive. Ce script affiche le message Still alive!lorsque je l'exécute, indiquant que le script s'est exécuté jusqu'à son terme. Voyez-vous un comportement différent?
Lily Finley
7
vous avez raison, il inverse le statut de sortie, mais ne plante pas le script lorsque la commande se termine par 0 ou 1. J'étais inattentif. Quoi qu'il en soit, merci d'avoir cité la documentation, j'ai mis mon expression à la ifclause et résolu le problème.
Marboni
42

Au lieu de "renvoyer vrai", vous pouvez également utiliser l'utilitaire "noop" ou null (comme indiqué dans les spécifications POSIX ) :et simplement "ne rien faire". Vous économiserez quelques lettres. :)

#!/usr/bin/env bash
set -e
man nonexistentghing || :
echo "It's ok.."
Timo
la source
3
bien que ||: n'est pas aussi clair que || vrai (ce qui peut dérouter les utilisateurs non experts), j'aime la concision
David
Cette variante ne renvoie aucun texte pouvant être important dans CI.
kivagant
5

Si vous souhaitez éviter l'échec de votre script et collecter le code retour:

command () {
    return 1  # or 0 for success
}

set -e

command && returncode=$? || returncode=$?
echo $returncode

returncode est collectée, que la commande réussisse ou échoue.

volingas
la source
2

J'ai utilisé l'extrait de code ci-dessous lorsque je travaille avec des outils CLI et je veux savoir si certaines ressources existent ou non, mais je ne me soucie pas de la sortie.

if [ -z "$(cat no_exist 2>&1 >/dev/null)" ]; then
    echo "none exist actually exist!"
fi
Payman
la source
1
Cela semble être un moyen vraiment détourné et modérément cher de direif [ -r not_exist ]
tripleee
1

J'aime un peu cette solution:

: `particular_script`

La commande / le script entre les ticks arrière est exécuté et sa sortie est envoyée à la commande ":" (qui est l'équivalent de "true")

$ false
$ echo $?
1
$ : `false`
$ echo $?
0

edit: Correction d'une faute de frappe

Q-life
la source
0

tandis que || trueest préféré, mais vous pouvez également faire

var=$(echo $(exit 1)) # it shouldn't fail
Foto Blysk
la source
0

À partir d'ici, aucune solution n'a fonctionné, alors j'en ai trouvé une autre:

set +e
find "./csharp/Platform.$REPOSITORY_NAME/obj" -type f -iname "*.cs" -delete
find "./csharp/Platform.$REPOSITORY_NAME.Tests/obj" -type f -iname "*.cs" -delete
set -e

Ceci est utile pour CI et CD. De cette façon, les messages d'erreur sont imprimés mais l'ensemble du script continue de s'exécuter.

Konard
la source
0
output=$(*command* 2>&1) && exit_status=$? || exit_status=$?
echo $output
echo $exit_status

Exemple d'utilisation pour créer un fichier journal

log_event(){
timestamp=$(date '+%D %T') #mm/dd/yy HH:MM:SS
echo -e "($timestamp) $event" >> "$log_file"
}

output=$(*command* 2>&1) && exit_status=$? || exit_status=$?

if [ "$exit_status" = 0 ]
    then
        event="$output"
        log_event
    else
        event="ERROR $output"
        log_event
fi
Robert.C
la source
0

Merci pour la solution simple ci-dessus:

<particular_script/command> || true

La construction suivante peut être utilisée pour des actions / dépannage supplémentaires des actions de script et des options de contrôle de flux supplémentaires:

if <particular_script/command>
then
   echo "<particular_script/command> is fine!"
else
   echo "<particular_script/command> failed!"
   #exit 1
fi

Nous pouvons freiner les actions supplémentaires et exit 1si nécessaire.

Almaz Gareev
la source