Devolver un valor de una función bash

10

Tengo una función que devuelve 1 si el número es un número válido de diez dígitos:

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
}

Está siendo llamado por:

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

La función funciona bien si el número es válido pero muestra un error de sintaxis si ingresa un número no válido.

usuario2179293
fuente

Respuestas:

14

La respuesta de @ choroba es correcta, sin embargo, este ejemplo podría ser más claro:

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

Este ejemplo es un poco más largo (configurando y $valNumResultluego consultando ese valor), pero describe más explícitamente lo que sucede: eso valNum()devuelve un valor, y ese valor puede consultarse y probarse.

PD Por favor, hazte un favor y devuelve 0para truey no cero para false. De esa manera, puede usar el valor de retorno para indicar "por qué fallamos" en el caso de falla.


fuente
8

Las funciones en bash solo pueden devolver códigos de salida. La sustitución de comandos, por el contrario, se utiliza para obtener la salida estándar de un comando o función. Por lo tanto, para verificar el indicador devuelto, no necesita la sustitución:

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

Pero, para que funcione, debe devolver 0 si el número es válido y 1 si no lo es (el código de salida 0 significa que no hay error).

choroba
fuente
No lo entiendo En el ejemplo 24.7 en tldp.org/LDP/abs/html/complexfunct.html, la función devuelve el valor máximo y no el código de salida. Aunque su sugerencia está funcionando pero no puedo entender por qué está funcionando
usuario2179293
1
dado que su prueba es averiguar si la entrada es un entero válido de 10 dígitos o no, es decir, verdadero o falso, la función devuelve 0 o 1. El ejemplo de choroba funciona porque if valnum "$num"es equivalente a if valnum "$num" = 0es decir, "si es verdadero". La regla básica en las secuencias de comandos sh es que 0 = verdadero / éxito, distinto de cero = falso / error.
cas
2
Por cierto, esa "Guía avanzada de secuencias de comandos Bash" no es una muy buena guía: está equivocado sobre muchas cosas y alienta algunas prácticas de secuencias de comandos pobres. Las preguntas frecuentes de Bash en mywiki.wooledge.org/BashFAQ son recursos mucho mejores.
cas
su función falla porque está haciendo eco de la cadena "Número inválido", y luego está haciendo una comparación numérica entre esa cadena y el número 1 conif [[ $(valNum $num) -eq 1 ]]
cas
5

No puede devolver un resultado arbitrario de una función de shell. Solo puede devolver un código de estado que sea un número entero entre 0 y 255. (Si bien puede pasar un valor mayor a return, es un módulo 256 truncado). El valor debe ser 0 para indicar el éxito y un valor diferente para indicar el error; por convención, debe atenerse a los códigos de error entre 1 y 125, ya que los valores más altos tienen un significado especial (comando externo incorrecto para 126 y 127, eliminado por una señal para valores más altos).

Como está devolviendo un resultado de sí o no aquí, es apropiado un código de estado. Como flagparece indicar un éxito o un fracaso, debe usar los valores convencionales de 0 para el éxito y 1 para el fracaso (lo contrario de lo que escribió). Luego puede usar su función directamente en una declaración 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

Si necesita discriminar entre códigos de falla, llame a la función directamente. Inmediatamente después de que regrese, el código de falla está disponible en $?. Luego puede verificarlo con una declaración de caso:

valNum "$num"
case $? in 

Si necesita usar el código de estado más tarde, guárdelo en otra variable antes $?de que el siguiente comando lo sobrescriba.

valNum "$num"
valNum_status=$?

Lo que escribió no funcionó porque la sustitución del comando se $(…)expande a la salida de la función, que en su código es el mensaje de error o está vacía, nunca 1.

Si necesita pasar más información de la que permite un código de estado de las funciones de un shell, tiene dos posibilidades:

  • Imprima algo de texto en la salida estándar y llame a la función en una sustitución de comando: $(valNum "$num")
  • Asigne a una o más variables dentro de la función y lea esas variables más tarde.
Gilles 'SO- deja de ser malvado'
fuente
2

He tenido resultados contradictorios en esta área yo mismo. Aquí están los resultados de mis experimentos empíricos. En primer lugar, alguna ' teoría ' sobre los comandos bash o * nix:

  • ÉXITO == 0 ... a saber. sin código de estado de error)
  • FAIL! = 0 ...... algún código de estado

Ejemplo:

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

Salida:

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

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

Como se muestra, el lscomando devuelve el código de estado = 2. Cuando intenta un directorio válido, el estado es cero ( 0 ). No es lo mismo que casi todos los demás idiomas.

regla # 1 - Hacer ...

  • VERDADERO == 0
  • FALSO! = 0

Debemos recordar que estamos probando códigos de error en una ifdeclaración Bash . Configuré constantes, o puedes usar shell trueo falsecomandos.

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

y salida:

Invalid Number
Not lucky.

Sin embargo, le sugiero que dé un voto positivo a @Gilles porque su respuesta es la correcta. Solo quería obtener el lado simplista en ePaper.

Solo otra cosa, el testcomando. Esto se ve así:

[[ some-expression ]]; 

La mayor parte del tiempo Y por ejemplo:

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

Cero (0) siendo cierto . ¿Por qué? Bueno, la página del manual dice que un solo argumento es ' verdadero ' cuando NO ES NULO.

referencias:

será
fuente