info:bash:pipeline:code_retour

Gérer les codes retours des commandes en pipelines

les pipelines en bash, rappel: Ils permettent d’enchaîner des commandes en passant le résultat (stdout), mais pas le code retour, d'une commande a la suivante.

commande 1 | commande 2 | commande 3 ....

exemple:

ls -AdU1 /existe/pas/* | tail -1
echo $?
0

Les lignes de commandes avec des pipes renvoi le code retour de la dernière commande. dans l'exemple ci-dessus, si le répertoire /existe/pas/ n'existe pas, le code retour sera quand même, et toujours, celui de la commande “tail -1”, c'est a dire 0
Pour gérer les codes retours des commandes a l’intérieur des pipelines, il existe des solutions, voir ci-dessous.

Pour une ligne de commande avec des pipes, le tableau de variable PIPESTATUS[] va afficher le code retour des commandes du pipe, en commençant a 0 pour la première commande.
PIPESTATUS[] se comporte comme un tableau bash.

A noter pour les exemples: “exit” permet de quitter un shell ou un sous-shell avec un code retour. Hors la première commande d'un pipe s’exécute dans le shell courant. Si vous mettez exit, le shell courant est fermé et la suite du script n'est pas exécuté. Un pipe ouvre un sous-shell et la commande “exit” permet de quitter ce sous-shell créé par le pipe “|”. Vous ne quittez donc pas le shell d'origine.

Pour la commande ci-dessous, la variable PIPESTATUS[0] renvoi le code retour de “true”, soit 0

true | exit 10 | exit 20 | exit 30 | exit 40 | exit 50 | exit 60
echo "\${PIPESTATUS[0]}=${PIPESTATUS[0]}"
0

Pour la commande ci-dessous, la variable PIPESTATUS[4] renvoi le code retour de la 5e commande “exit 40”, soit 40

true | exit 10 | exit 20 | exit 30 | exit 40 | exit 50 | exit 60
echo "\${PIPESTATUS[4]}=${PIPESTATUS[4]}"
${PIPESTATUS[4]}=40
true | exit 10 | exit 20 | exit 30 | exit 40 | exit 50 | exit 60
echo -e "\${PIPESTATUS[0]}=${PIPESTATUS[0]}\n\${PIPESTATUS[1]}=${PIPESTATUS[1]}\n\${PIPESTATUS[2]}=${PIPESTATUS[2]}\n\
\${PIPESTATUS[3]}=${PIPESTATUS[3]}\n\${PIPESTATUS[4]}=${PIPESTATUS[4]}\n\${PIPESTATUS[5]}=${PIPESTATUS[5]}\n\
\${PIPESTATUS[6]}=${PIPESTATUS[6]}"
${PIPESTATUS[0]}=0
${PIPESTATUS[1]}=10
${PIPESTATUS[2]}=20
${PIPESTATUS[3]}=30
${PIPESTATUS[4]}=40
${PIPESTATUS[5]}=50
${PIPESTATUS[6]}=60

Pour afficher tous les codes retour des commandes du pipeline:

true | exit 11 | exit 22 | exit 33 | exit 44 | exit 55 | exit 66
echo "${PIPESTATUS[@]}"
0 11 22 33 44 55 66

les codes retours différents de 0 d'une commande a l’intérieur d'un pipeline est souvent un problème notamment dans les scripts ou dans les commandes Ansible.
L'option “pipefail” stop/arrête l’exécution du pipeline sur la commande en erreur, c'est a dire, lorsque le code retour d'une des commandes est différent de 0.

#!/usr/bin/env bash
set -o pipefail
....
grep "chaine" /non/existent/fichier | tail -1
if  [[ $? == 0 ]] 
do 
    printf "l execution a réussi\n"
else
    printf "échec de la recherche\n"

Dans une commande Ansible vous pouvez utiliser l'option en début de ligne, et elle sera valable pour toute la ligne.
Vous pouvez ainsi récupérer le code retour d'erreur du pipeline avec un arrêt de l’enchaînement des commandes par pipe sur la commande en erreur. par exemple:

- name: Recuperer le nom de répertoire numérique de la version la plus élevé dans /opt/rep/nn/
  shell: set -o pipefail && cd /opt/{{ rep }}/ && ls -AdU1 ?? | tail -1
  register: rep_version
  • /home/franck/dokuwiki/doc/data/pages/info/bash/pipeline/code_retour.txt
  • Dernière modification : 2022/12/03 10:50
  • de franck