Affectation de code de sortie à une variable locale du shell

42
#!/bin/bash
function0()
{
 local t1=$(exit 1)
 echo $t1
}

function0

echoaffiche la valeur vide. J'esperais:

1

Pourquoi la t1variable n'est-elle pas affectée à la valeur de retour de la commande exit - 1?

Gilles, arrête de faire le mal
la source

Réponses:

58

local t1=$(exit 1) demande au shell de:

  • courir exit 1dans une sous-coque;
  • stocke sa sortie (en tant que dans, le texte qu'il sort en sortie standard) dans une variable t1locale à la fonction.

C'est donc normal que ça t1finisse par être vide.

( $()est connu comme substitution de commande .)

Le code de sortie est toujours attribué à $?, vous pouvez donc le faire

function0()
{
  (exit 1)
  echo "$?"
}

pour obtenir l'effet que vous recherchez. Vous pouvez bien sûr affecter $?à une autre variable:

function0()
{
  (exit 1)
  local t1=$?
  echo "$t1"
}
Stephen Kitt
la source
1
Vous savez, vous pouvez toujours mettre le retour dans le tuyau, aussi. `$ (trap 'printf" :: ERRNO: $? "' 0; # faites maintenant ce que vous voudrez - ce piège garantira que la dernière chaîne écrite est le dernier retour pour le contexte de substitution complet.
mikeserv le
1
@mikeserv avez-vous manqué un backtick? $(trap 'printf "::ERRNO:$?"' 0; # now do whatever however
Doktor J
12

Le code de sortie a été stocké dans $? variable. En utilisant uniquement les commandes de substitution pour capturer la sortie, vous devez utiliser (...) pour créer un sous - shell :

#!/bin/bash

func() {
  (exit 1)
  local t1=$?
  printf '%d\n' "$t1"
}

func
cuonglm
la source
le but de la mission t1=$?est de l'utiliser, non? et ne serait pas $?obstrué par l'opération cession? Je suppose que je demande si cela ne devrait pas êtreprintf '%d\n' "${t1}"
Dani_l
@Dani_l: Merci, c'est une faute de frappe. Mis à jour.
jeudi
Notez que la substitution de commande ne capture que la sortie standard sauf si elle est redirigée différemment.
Phyatt
7

Dans bashcela fonctionne:

loc(){  local   "x=$(exit "$1"):$?"
        printf  '$%s:\t%d\n' \
                 x "${x##*:}" \? "$?"
}

Cela concerne l'ordre d'évaluation des commandes et l'affectation des variables. locala une valeur de retour qui lui est propre - et il s’agit de la commande en cours d’exécution, pas de la substitution de commande. La raison pour laquelle les choses aiment ...

x=$(exit 1); echo "$?"

... may return 1 est parce qu'il n'y a jamais de retour dans cette commande, à l'exception du sous-shell exécuté pour affecter $xla valeur, de manière à $?ne pas être bouleversé, comme c'est le cas dans pratiquement tous les autres cas dans lesquels des substitutions de commandes sont utilisées.

Quoi qu'il en soit, avec localelle ne faussés - mais si vous attrapez juste au bon moment - qui est alors que les extensions sont encore en cours d' évaluation et avant local les routines « ont une chance de écraserait - vous pouvez affecter encore.

unset x; loc 130; echo "${x-\$x is unset}"

... des impressions ...

$x: 130
$?: 0
$x is unset

Vous devez savoir cependant que dans de nombreux obus, vous ne pouvez pas compter sur $?une évaluation à mi-parcours de cette manière. En fait, c'est probablement parce que ces coquilles ne se donnent pas la peine de réévaluer à tout moment, comme peut bash- être , ce qui, à mon avis, est probablement meilleur que bashle s. Voulez-vous vraiment que votre interprète évalue de manière récursive les valeurs d'évaluation de boucle qui risquent très fort d'être écrasées avant que vous n'ayez la chance de les utiliser?

Quoi qu'il en soit, c'est comme ça que vous pouvez faire ça.

Mikeserv
la source
-1

En fonction de la raison pour laquelle vous essayez d’obtenir le code de sortie, vous pouvez également exécuter une opération if some-command; then echo "Success $?"; else echo "Failure $?"; fiqui ne fait rien avec le résultat de la commande. Elle évalue simplement le code de sortie de la commande exécutée. Vous pouvez ajouter or( or$ ( around the command and you'll still get the same results. A better example might besi grep -q 'somestring' un fichier; puis echo "le code de sortie trouvé est $?"; Sinon "vous n'avez pas trouvé le code de sortie est $?"; Fi`.

Vous pouvez également tester le code de retour d'une fonction qui peut être un return 3code de retour explicite ou implicite qui est le résultat de la dernière commande. Dans ce cas, vous devez faire attention à ce que vous n'ayez pas de echofin à la fin. fonction, sinon il masque / réinitialise le code de sortie précédent.

command_last () {
  echo "True is `true`"
  echo "False is `false`"
  false
}
command_last; echo $?
# Outputs:
# True is 0
# False is 1
# 1

echo_last () {
  echo "True is `true`"
  echo "False is `false`"
  false
  # echo'ing literally anything (or nothing) returns true aka exit 0
  echo
}
echo_last; echo $?
# Outputs:
# True is 0
# False is 1
#            # Blank line due to empty echo
# 0

Enfin, un truc sale car vous ne pouvez pas le faire VAR=(SOME_COMMAND)car il VAR=()s’agit d’une définition de tableau VAR=( $(echo 'Some value') ).

dragon788
la source
Toutes les sorties revendiquées sont fausses, du fait que la substitution de commande ne donne pas le code de sortie, ce qui est le but de la question. On ne sait pas ce que le "sale tour" a à faire avec quoi que ce soit.
Nick Matteo