Przypisywanie kodu wyjścia do lokalnej zmiennej powłoki

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

function0

echowyświetla pustą wartość. Oczekiwałem:

1

Dlaczego t1zmienna nie otrzymuje wartości zwracanej przez komendę exit - 1?

Gilles „SO- przestań być zły”
źródło

Odpowiedzi:

58

local t1=$(exit 1) mówi powłoce, aby:

  • uruchomić exit 1w podpowłoce;
  • zapisz jego wynik (jak w tekście, który wypisuje na standardowe wyjście) w zmiennej t1lokalnej dla funkcji.

Jest to więc normalne, że t1kończy się puste.

( $()jest znany jako podstawianie poleceń ).

Kod wyjścia jest zawsze przypisany $?, więc możesz to zrobić

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

aby uzyskać efekt, którego szukasz. Możesz oczywiście przypisać $?inną zmienną:

function0()
{
  (exit 1)
  local t1=$?
  echo "$t1"
}
Stephen Kitt
źródło
1
Wiesz, zawsze możesz również umieścić zwrot w rurze. `$ (trap 'printf" :: ERRNO: $? "' 0; # teraz rób cokolwiek jednak - ta pułapka zapewni, że ostatni napisany łańcuch będzie ostatnim zwrotem dla całego kontekstu podstawienia.
mikeserv
1
@mikeserv przegapiłeś backtick? $(trap 'printf "::ERRNO:$?"' 0; # now do whatever however
Doktor J
12

Kod wyjścia został zapisany w $? zmienna. Używanie podstawiania poleceń tylko do przechwytywania danych wyjściowych, należy użyć (...), aby utworzyć podpowłokę :

#!/bin/bash

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

func
Cuonglm
źródło
celem zadania t1=$?jest wykorzystanie go, nie? i czy nie dałoby $?się zapchać opcją przydziału? Chyba pytam, czy nie powinno byćprintf '%d\n' "${t1}"
Dani_l,
@Dani_l: Dzięki, to pomyłka. Zaktualizowano
cuonglm
Zauważ, że zastępowanie poleceń wychwytuje tylko standardowe, chyba że zostanie przekierowane inaczej.
phyatt
7

W bashtym działa:

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

Ma to związek z kolejnością oceny poleceń i przypisywaniem zmiennych. localma własną wartość zwracaną - i jest to aktualnie wykonywane polecenie, a nie podstawienie polecenia. Przyczyna takich rzeczy jak ...

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

... może zwrócić 1, ponieważ nigdy nie ma powrotu w tej komendzie, z wyjątkiem uruchomienia podpowłoki w celu przypisania $xwartości - więc $?nie ulega zablokowaniu, jak ma to miejsce praktycznie w każdym innym przypadku, w którym stosowane są podstawienia komend.

W każdym razie, ze localto ma dostać niszczona - ale jeśli złapiesz go w odpowiednim momencie - który jest jednocześnie ekspansje są nadal oceniane i przed local „s procedury mają szansę go sprać - nadal można przypisać go.

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

... drukuje ...

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

Powinieneś jednak wiedzieć, że w wielu powłokach nie możesz polegać na $?ustawieniu w połowie oceny w ten sposób. W rzeczywistości jest tak prawdopodobnie dlatego, że te powłoki nie przeszkadzają w ponownej ocenie w każdym możliwym momencie, jak być może bash- co, moim zdaniem, jest prawdopodobnie lepszym zachowaniem niż bashjego. Czy naprawdę chcesz, aby Twój interpreter rekurencyjnie sprawdzał wartości, które najprawdopodobniej zostaną nadpisane, zanim będziesz miał okazję ich użyć?

W każdym razie tak możesz to zrobić.

mikeserv
źródło
-1

W zależności od tego, dlaczego próbujesz po prostu uzyskać kod wyjścia, możesz również uruchomić, if some-command; then echo "Success $?"; else echo "Failure $?"; fiktóry nie robi nic z wynikiem polecenia, po prostu ocenia kod wyjścia uruchomienia polecenia. Możesz dodać or( or$ ( around the command and you'll still get the same results. A better example might bejeśli grep -q 'somestring' somefile; następnie powtórz echo: „Znaleziono kod wyjścia somestring to $?”; W innym przypadku „Nie znalazłeś kodu wyjścia somestring to $?”; Fi`.

Możesz również przetestować kod powrotu funkcji, który może być jawnym return 3lub dorozumianym kodem powrotu, który jest wynikiem ostatniego polecenia, w takim przypadku musisz uważać, aby nie mieć echona końcu funkcja, w przeciwnym razie maskuje / resetuje poprzedni kod wyjścia.

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

Wreszcie brudna sztuczka, ponieważ nie możesz tego zrobić, VAR=(SOME_COMMAND)ponieważ VAR=()jest to definicja tablicy, więc musisz VAR=( $(echo 'Some value') ).

dragon788
źródło
Wszystkie deklarowane dane wyjściowe są błędne, ponieważ podstawienie polecenia nie daje kodu wyjścia, co jest sednem pytania. Nie jest jasne, co ta „sztuczka” ma z tym wspólnego.
Nick Matteo,