Restituisce un valore da una funzione bash


10

Ho una funzione che restituisce 1 se il numero è un numero di dieci cifre valido:

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
}

Viene chiamato da:

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

La funzione funziona correttamente se il numero è valido ma mostra un errore di sintassi se si inserisce un numero non valido.

Risposte:


14

La risposta di @ choroba è corretta, tuttavia questo esempio potrebbe essere più chiaro:

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

Questo esempio è un po 'più lungo (impostazione $valNumResultquindi interrogazione di quel valore), ma descrive in modo più esplicito cosa succede: che valNum()restituisce un valore e quel valore può essere interrogato e testato.

PS Per favore, fatevi un favore e ritornate 0per truee diverso da zero false. In questo modo è possibile utilizzare il valore restituito per indicare "perché non siamo riusciti" nel caso di errore.


8

Le funzioni in bash possono solo restituire codici di uscita. La sostituzione dei comandi, al contrario, viene utilizzata per ottenere l'output standard di un comando o di una funzione. Pertanto, per controllare la bandiera restituita, non è necessaria la sostituzione:

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

Tuttavia, affinché funzioni, è necessario restituire 0 se il numero è valido e 1 in caso contrario (il codice di uscita 0 non indica alcun errore).


Non capisco. Nell'esempio 24.7 in tldp.org/LDP/abs/html/complexfunct.html la funzione restituisce il valore massimo e non il codice di uscita. Sebbene il tuo suggerimento
funzioni,

1
poiché il tuo test è scoprire se l'ingresso è un intero valido di 10 cifre oppure no, cioè vero o falso, la funzione restituisce 0 o 1. L'esempio di choroba funziona perché if valnum "$num"equivale ad if valnum "$num" = 0esempio "se è vero". la regola empirica di base nello scripting sh è che 0 = vero / successo, diverso da zero = falso / errore.
Cas

2
A proposito, quella "Guida avanzata di script Bash" non è una guida molto buona - è sbagliata su molte cose e incoraggia alcune cattive pratiche di scripting. le FAQ di Bash su mywiki.wooledge.org/BashFAQ sono risorse molto migliori.
Cas


la tua funzione non riesce perché fa eco alla stringa "Numero non valido" e quindi fai un confronto numerico tra quella stringa e il numero 1 conif [[ $(valNum $num) -eq 1 ]]
cas

5

Non è possibile restituire un risultato arbitrario da una funzione shell. È possibile restituire solo un codice di stato che è un numero intero compreso tra 0 e 255. (Mentre è possibile passare un valore maggiore a return, viene troncato modulo 256.) Il valore deve essere 0 per indicare l'esito positivo e un valore diverso per indicare l'errore; per convenzione dovresti attenersi a codici di errore tra 1 e 125, poiché i valori più alti hanno un significato speciale (comando esterno errato per 126 e 127, ucciso da un segnale per valori più alti).

Poiché stai restituendo un risultato sì-o-no qui, un codice di stato è appropriato. Poiché flagsembra indicare un successo o un fallimento, dovresti usare i valori convenzionali di 0 per il successo e 1 per il fallimento (l'opposto di quello che hai scritto). È quindi possibile utilizzare la funzione direttamente in un'istruzione 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

Se è necessario discriminare tra i codici di errore, chiamare direttamente la funzione. Immediatamente dopo la sua restituzione, il codice di errore è disponibile in $?. È quindi possibile verificarlo con un'istruzione case:

valNum "$num"
case $? in 

Se è necessario utilizzare il codice di stato in un secondo momento, salvarlo in un'altra variabile prima che $?venga sovrascritto dal comando successivo.

valNum "$num"
valNum_status=$?

Quello che hai scritto non ha funzionato perché la sostituzione del comando si $(…)espande nell'output della funzione, che nel tuo codice è o il messaggio di errore o vuoto, mai 1.

Se è necessario passare più informazioni di quelle consentite da un codice di stato da una shell, ci sono due possibilità:

  • Stampa del testo sull'output standard e chiama la funzione in una sostituzione di comando: $(valNum "$num")
  • Assegna a una o più variabili all'interno della funzione e leggi quelle variabili in seguito.

2

Ho avuto risultati contrastanti in questo settore da solo. Ecco i risultati dei miei esperimenti empirici. Innanzitutto, alcune " teorie " sui comandi bash o * nix:

  • SUCCESSO == 0 ... vale a dire. nessun codice stato errore)
  • FAIL! = 0 ...... un codice di stato

Esempio:

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

Produzione:

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

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

Come mostrato, il lscomando restituisce il codice di stato = 2. Quando si tenta una directory valida, lo stato è zero ( 0 ). Non uguale a quasi tutte le altre lingue.

regola n. 1 - Crea ...

  • VERO == 0
  • FALSO! = 0

Dobbiamo ricordare che stiamo testando i codici di errore in ifun'istruzione Bash . Ho impostato costanti, oppure puoi usare shell trueo falsecomandi.

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

e uscita:

Invalid Number
Not lucky.

Tuttavia, ti suggerisco di dare un " voto positivo" a @Gilles perché la sua risposta è corretta. Volevo solo scoprire il lato semplicistico di ePaper.

Solo un'altra cosa, il testcomando. Questo sembra:

[[ some-expression ]]; 

La maggior parte delle volte. E per esempio:

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

Zero (0) è vero . Perché? Bene, la pagina man dice che un singolo argomento è " vero " quando NON è NULL.

Riferimenti:

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.