Zuweisen von Exit-Code zu einer lokalen Shell-Variablen

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

function0

echogibt leeren Wert aus. Ich erwartete:

1

Warum wird der t1Variable nicht der Rückgabewert des Befehls exit zugewiesen - 1?

Gilles 'SO - hör auf böse zu sein'
quelle

Antworten:

58

local t1=$(exit 1) Weist die Shell an:

  • laufen exit 1in einer Subshell;
  • Speichern Sie die Ausgabe (wie in) in einer Variablen t1, die für die Funktion lokal ist.

Es ist also normal, dass t1es leer bleibt.

( $()Wird als Befehlsersetzung bezeichnet .)

Der Beendigungscode ist immer zugewiesen $?, damit Sie dies tun können

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

um den gewünschten Effekt zu erzielen. Sie können natürlich $?eine andere Variable zuweisen :

function0()
{
  (exit 1)
  local t1=$?
  echo "$t1"
}
Stephen Kitt
quelle
1
Sie können den Rücklauf auch immer in die Leitung stecken. `$ (trap 'printf" :: ERRNO: $? "' 0; # jetzt mache aber was auch immer - dieser Trap wird sicherstellen, dass der zuletzt geschriebene String die letzte Rückgabe für den gesamten Substitutionskontext ist.
mikeserv
1
@mikeserv hast du ein Backtick verpasst? $(trap 'printf "::ERRNO:$?"' 0; # now do whatever however
Doktor J
12

Exit-Code wurde in $ gespeichert ? Variable. Mit Befehl Substitution nur die Ausgabe erfassen, sollten Sie (...) Subshell zu erstellen :

#!/bin/bash

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

func
cuonglm
quelle
der zweck der aufgabe t1=$?ist es, sie zu benutzen, nein? und würde nicht $?durch den Einsatz op überfordert werden? Ich schätze, ich printf '%d\n' "${t1}"
frage
@Dani_l: Danke, das ist ein Tippfehler. Aktualisiert.
Dienstag,
Beachten Sie, dass die Befehlsersetzung nur die Standardausgabe erfasst, sofern keine andere Umleitung erfolgt.
Phyatt
7

In bashdiesem Werk:

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

Dies hat mit der Reihenfolge der Befehlsauswertung und der Variablenzuweisung zu tun. localhat einen eigenen Rückgabewert - und es ist der aktuell ausgeführte Befehl, nicht die Befehlsersetzung. Der Grund Dinge wie ...

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

... kann 1 zurückgeben, weil es in diesem Befehl nie eine Rückkehr gibt, mit Ausnahme des Subshell-Laufs, um $xden Wert zuzuweisen - es wird $?also nicht blockiert, wie es in praktisch jedem anderen Fall der Fall ist, in dem Befehlsersetzungen verwendet werden.

Wie auch immer, mit localihm nicht bekommen verprügelt - aber wenn man ihm genau zum richtigen Zeitpunkt erwischen - das ist , während die Erweiterungen noch ausgewertet werden und vor local ‚s Routinen eine Chance haben , es zu verprügeln - Sie können es nach wie vor zu.

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

... druckt ...

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

Sie sollten jedoch wissen, dass Sie sich in vielen Shells nicht darauf verlassen können, $?dass Sie auf diese Weise die Mitte der Bewertung festlegen. Tatsächlich liegt das wahrscheinlich daran, dass diese Muscheln sich nicht die Mühe machen, zu jedem möglichen Zeitpunkt neu zu bewerten, wie dies vielleicht der bashFall ist - was meiner Meinung nach wahrscheinlich besseres Verhalten ist als bashdas von. Möchten Sie wirklich, dass Ihr Interpreter Werte rekursiv in einer Schleife auswertet, die sehr wahrscheinlich überschrieben werden, bevor Sie die Möglichkeit haben, sie zu verwenden?

Wie auch immer, so kannst du das machen.

mikeserv
quelle
-1

Je nachdem, warum Sie versuchen, nur den Exit-Code abzurufen, können Sie auch nur ausführen, if some-command; then echo "Success $?"; else echo "Failure $?"; fiwas nichts mit der Ausgabe des Befehls zu tun hat. Es wird lediglich der Exit-Code des ausgeführten Befehls ausgewertet. Sie können or( or$ ( around the command and you'll still get the same results. A better example might bewenn grep -q 'somestring' somefile; dann echo "gefunden somestring Exit-Code ist $?"; Sonst "nicht gefunden somestring Exit-Code ist $?"; Fi`.

Sie können auch den Rückkehrcode einer Funktion testen, die entweder ein expliziter return 3oder ein impliziter Rückkehrcode sein kann, der das Ergebnis des letzten Befehls ist. In diesem Fall müssen Sie darauf achten, dass echoam Ende des Befehls kein steht Funktion, andernfalls wird der vorherige Beendigungscode maskiert / zurückgesetzt.

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

Schließlich ein schmutziger Trick, den Sie nicht machen können, VAR=(SOME_COMMAND)weil VAR=()es eine Array-Definition ist, die Sie brauchen VAR=( $(echo 'Some value') ).

dragon788
quelle
Alle behaupteten Ausgaben sind falsch, da die Befehlsersetzung nicht den Exit-Code liefert, was der springende Punkt der Frage ist. Es ist nicht klar, was der "schmutzige Trick" mit irgendetwas zu tun hat.
Nick Matteo