Comment faire pour que `local` capture le code de sortie?

11

Dans mon projet, j'ai l'extrait suivant:

local output="$(bash "${1##*/}")"
echo "$?"

Cela affiche toujours zéro en raison de la localsuppression, cependant, localentraîne le $?comportement correct de la variable: ce qui suppose le code de sortie du sous-shell.

Ma question est: comment puis-je garder cette variable locale tout en capturant la valeur de sortie?

Ultimate Hawk
la source
1
shellcheckne détectera pas seulement ce problème mais suggérera la solution sur unix.stackexchange.com/a/281749/24718 !
Waleed Khan

Réponses:

16
#!/bin/bash
thing() {
   local foo=$(asjkdh) ret="$?"
   echo "$ret"
}

Cela fera écho 127, le code d'erreur correct pour "commande introuvable".

Vous pouvez utiliser localpour définir plusieurs variables. Je crée donc également la variable locale RETpour capturer le code de sortie du sous-shell avant de localréussir et de mettre $?à zéro.

DopeGhoti
la source
Est-il garanti que bashcette expression est évaluée de gauche à droite?
Max Ried
Pour autant que je sache, les affectations de variables sont en ordre, de gauche à droite dans ce contexte, oui.
DopeGhoti
@MaxRied le fait que cela fonctionne de manière fiable semble indiquer que oui, c'est le cas. Cependant, je ne trouve aucune information à ce sujet ni dans POSIX ni dans bashle manuel de référence.
chat
10
En passant, l'utilisation de noms de variables en majuscules est une mauvaise forme. Voir la spécification de variable d'environnement POSIX sur pubs.opengroup.org/onlinepubs/009695399/basedefs/… , qui décrit les noms tout en majuscules comme réservés aux variables ayant une signification pour le shell ou le système et les noms avec au moins un caractère en minuscule réservé à une utilisation définie par l'application, en gardant à l'esprit que les variables shell et les variables d'environnement partagent un espace de noms (puisque, en cas de collision, l'affectation au premier peut remplacer le second).
Charles Duffy
Les commentaires ne sont pas pour une discussion approfondie; cette conversation a été déplacée vers le chat .
terdon
27

Déclarez la variable locale avant de lui affecter:

thing() {
  local output
  output="$(bash "${1##*/}")"
  echo "$?"
}

À mon avis, cela est également plus lisible que la définition d'une RETvariable supplémentaire . YMMV là-dessus, mais cela fonctionne exactement comme vous vous en doutez.

Caractère générique
la source
2
C'est bien mieux que d'utiliser une variable séparée, comme cela devrait être évident si vous voulez vérifier le code retour de plusieurs affectations: simplement local var1 var2 ...et Bob est votre oncle.
l0b0
@ l0b0 Bob est mon oncle. : D
chat