Zwracanie wartości z funkcji bash

10

Mam funkcję, która zwraca 1, jeśli liczba jest poprawną dziesięciocyfrową liczbą:

valNum()
{
    flag=1
    if [[ $1 != [1-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] ]]; then
        echo "Invalid Number"
        flag=0
    fi
    return $flag
}

Jest wywoływany przez:

if [[ $(valNum $num) -eq 1 ]]; then
      #do something
fi

Funkcja działa poprawnie, jeśli liczba jest poprawna, ale wyświetla błąd składniowy, jeśli wprowadzi niepoprawną liczbę.

użytkownik2179293
źródło

Odpowiedzi:

14

Odpowiedź @ choroba jest poprawna, jednak ten przykład może być jaśniejszy:

valNum $num
valNumResult=$? # '$?' is the return value of the previous command
if [[ $valNumResult -eq 1 ]]
then
  : # do something
fi

Ten przykład jest nieco dłuższy (ustawienie, $valNumResulta następnie zapytanie tej wartości), ale bardziej szczegółowo opisuje, co się dzieje: valNum()zwraca wartość, a tę wartość można zapytać i przetestować.

PS Zrób sobie przysługę i wróć 0za trueniezerową wartość false. W ten sposób możesz użyć wartości zwracanej do wskazania „dlaczego nam się nie udało” w przypadku awarii.


źródło
8

Funkcje w bash mogą zwracać tylko kody wyjścia. Z kolei podstawienie polecenia służy do uzyskania standardowego wyniku polecenia lub funkcji. Dlatego, aby sprawdzić zwróconą flagę, nie potrzebujesz podstawienia:

if valNum "$num" ; then
    # ...
fi

Aby jednak zadziałało, powinieneś zwrócić 0, jeśli liczba jest poprawna, i 1, jeśli nie jest (kod wyjścia 0 oznacza brak błędu).

choroba
źródło
Nie rozumiem. W przykładzie 24.7 w tldp.org/LDP/abs/html/complexfunct.html funkcja zwraca wartość maksymalną, a nie kod wyjścia. Chociaż twoja sugestia działa, ale nie jestem w stanie zrozumieć, dlaczego działa
użytkownik2179293
1
ponieważ twoim testem jest sprawdzenie, czy wejście jest prawidłową 10-cyfrową liczbą całkowitą, czy nie, tj. prawda czy fałsz, funkcja zwraca 0 lub 1. przykład choroby działa, ponieważ if valnum "$num"jest równoważny if valnum "$num" = 0np. „jeśli to prawda”. podstawową zasadą w skryptach sh jest to, że 0 = prawda / sukces, niezerowa = fałsz / błąd.
cas
2
BTW, ten „Advanced Bash-Scripting Guide” nie jest zbyt dobrym przewodnikiem - jest w błędzie w wielu sprawach i zachęca do złych praktyk skryptowych. FAQ Bash na mywiki.wooledge.org/BashFAQ jest znacznie lepszym zasobem.
cas
twoja funkcja zawodzi, ponieważ echo ciągu „Nieprawidłowy numer”, a następnie dokonuje się porównania liczbowego między tym ciągiem a liczbą 1 za pomocąif [[ $(valNum $num) -eq 1 ]]
cas
5

Nie można zwrócić dowolnego wyniku z funkcji powłoki. Możesz zwrócić tylko kod stanu, który jest liczbą całkowitą z przedziału od 0 do 255. (Chociaż możesz przekazać większą wartość return, jest on obcinany modulo 256.) Wartość musi wynosić 0, aby wskazać sukces, a inną wartość, aby wskazać niepowodzenie; zgodnie z konwencją powinieneś trzymać się kodów błędów od 1 do 125, ponieważ wyższe wartości mają specjalne znaczenie (złe zewnętrzne polecenie dla 126 i 127, zabite sygnałem dla wyższych wartości).

Ponieważ zwracasz tutaj wynik „tak lub nie”, kod statusu jest odpowiedni. Ponieważ flagwydaje się wskazywać na sukces lub porażkę, powinieneś użyć konwencjonalnych wartości 0 dla sukcesu i 1 dla niepowodzenia (odwrotnie niż to, co napisałeś). Następnie możesz użyć swojej funkcji bezpośrednio w instrukcji if.

valNum ()
{
  local flag=0
  if [[ $1 != [1-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] ]]; then
    echo 1>&2 "Invalid Number"
    flag=1
  fi
  return $flag
}
if valNum "$num"; then
  #do something
fi

Jeśli chcesz rozróżnić kody błędów, wywołaj funkcję bezpośrednio. Natychmiast po powrocie kod błędu jest dostępny w $?. Następnie możesz to sprawdzić za pomocą instrukcji case:

valNum "$num"
case $? in 

Jeśli chcesz później użyć kodu stanu, zapisz go w innej zmiennej, zanim $?zostanie zastąpiony przez następne polecenie.

valNum "$num"
valNum_status=$?

To, co napisałeś, nie zadziałało, ponieważ podstawienie polecenia $(…)rozwija się do wyniku funkcji, która w kodzie jest albo komunikatem o błędzie, albo pustą, nigdy 1.

Jeśli potrzebujesz przekazać więcej informacji, niż pozwala na to kod stanu z funkcji powłoki, masz dwie możliwości:

  • Wydrukuj tekst na standardowym wyjściu i wywołaj funkcję w podstawieniu polecenia: $(valNum "$num")
  • Przypisz jedną lub więcej zmiennych wewnątrz funkcji i przeczytaj te zmienne później.
Gilles „SO- przestań być zły”
źródło
2

Sam miałem sprzeczne wyniki w tej dziedzinie. Oto wyniki z moich eksperymentów empirycznych. Po pierwsze, niektóre „ teorie ” na temat poleceń bash lub * nix:

  • SUKCES == 0 ... mianowicie. brak kodu stanu błędu)
  • FAIL! = 0 ...... jakiś kod statusu

Przykład:

if  ls -lt /nonexistantdir
then 
    echo "found"
else
    echo "FAIL"
fi
#
echo
ls -lt /nonexistantdir; echo "status = $?"
echo "status = $?"

Wynik:

ls: cannot access '/nonexistantdir': No such file or directory
FAIL... 

ls: cannot access '/nonexistantdir': No such file or directory
status = 2

Jak pokazano, lspolecenie zwraca kod stanu = 2. Podczas próby prawidłowego katalogu status ma wartość zero ( 0 ). Nie taki sam jak prawie wszystkie inne języki.

reguła nr 1 - Make ...

  • PRAWDA == 0
  • FAŁSZ! = 0

Musimy pamiętać, że testujemy kody błędów w ifinstrukcji Bash . Ustawiam stałe lub możesz użyć powłoki truelub falsepoleceń.

TRUE=0
FALSE=1

#  valid number function
#
valNum()
{
    flag=$TRUE

    if [[ $1 != [1-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] ]]; then
        echo "Invalid Number"
        flag=$FALSE
    fi
    return $flag
}

#    later on ...
#
if validNum Abc 
then
    echo "Lucky number"
else
    echo "Not lucky."
fi

i wyjście:

Invalid Number
Not lucky.

Sugeruję jednak, abyś oddał głos na „Gilles”, ponieważ jego odpowiedź jest poprawna. Chciałem tylko upraszczać stronę ePaper.

Jeszcze jedno, testpolecenie. To wygląda jak:

[[ some-expression ]]; 

Większość czasu. I na przykład:

$ test 1
$ echo "result = $?"
result = 0
$ test 0
$ echo "result = $?"
result = 0

Zero (0) jest prawdą . Dlaczego? Otóż ​​strona podręcznika mówi, że pojedynczy argument jest „ prawdziwy ”, gdy NIE jest NULL.

Bibliografia:

będzie
źródło