¿Retorno implícito en funciones bash?

Digamos que tengo una función bash como esta:

gmx(){ echo "foo"; } 

¿funcionará implícitamente? devolver el valor de salida del comando echo, o es necesario utilizar return?

gmx(){ echo "foo"; return $? } 

Supongo que la forma bash funciona, el estado de salida del comando final de la función bash es el que se «devuelve», pero no es 100% seguro.

Respuesta

return hace un retorno explícito desde una función de shell o» dot script «(un script de origen). Si return no se ejecuta, se realiza una devolución implícita al final de la función de shell o el script dot.

Si return se ejecuta sin un parámetro, es equivalente a devolver el estado de salida del comando ejecutado más recientemente.

Así es como return funciona en todos los POSIX shells.

Por ejemplo,

gmx () { echo "foo" return "$?" } 

es equivalente a

gmx () { echo "foo" return } 

que es lo mismo que

gmx () { echo "foo" } 

En general, es muy raro que necesite usar $? en absoluto. En realidad, solo es necesario si necesita guardarlo para uso futuro, por ejemplo, si necesita investigar su valor varias veces (en cuyo caso, asignaría su valor a una variable y realizaría una serie de pruebas en esa variable).

Comentarios

  • Una desventaja de usar return es que para funciones definidas como f() (...; cmd; return), evita la optimización que hacen algunos shells al ejecutar cmd en el mismo proceso que el subshell. Con muchos shells, eso también significa que el estado de salida de la función no ‘ t lleva la información de que cmd se ha eliminado cuando se ha (la mayoría de los shells pueden ‘ t recuperar esa información de todos modos).
  • Tenga en cuenta que con pdksh y algunos de sus derivados (como OpenBSD sh o posh), ‘ necesitarías return -- "$?" si hubiera posibilidad de que el último comando fuera una función que devolviera un número negativo. mksh (también basado en pdksh) prohíbe que las funciones devuelvan valores negativos.
  • gracias, esto ayuda, supongo que no ‘ entiendo cómo return x funciona de manera diferente a exit x … lo único que sé es que return x no saldrá del proceso actual.
  • @AlexanderMills Bueno, ‘ es lo que dije: return se usa para regresar desde una función o un script de puntos. exit hace algo completamente diferente (termina un proceso).
  • sí, eso tiene sentido. Creo que estoy empezando a manejar mejor esto

Respuesta

Desde la bash(1) página de manual:

Cuando se ejecuta, el estado de salida de una función es el estado de salida del último comando ejecutado en el cuerpo.

Comentarios

  • correcto, y un corolario podría ser que la declaración de retorno no es más que el estado de salida.
  • Supongo que return es un comando incorporado, aunque return 1 es diferente de exit 1, etc., así que
  • » return [n]: hace que una función deje de ejecutarse y devuelva el valor especificado por n a su llamador. Si se omite n, el estado de retorno es el del último comando ejecutado en el cuerpo de la función. » (ibid) Entonces, return fuerza el estado de salida de una función a un valor específico si se especifica.
  • @AlexandwrMills Sí, return y exit son ambos integrados, excepto que return solo se puede usar dentro de la función. Puede ‘ t terminar un script con return. El estado de salida es el valor que devuelve el comando. return es un comando que devuelve ese valor. Entonces, la » declaración de retorno no es más que el estado de salida » simplemente no es del todo precisa. Uno es un valor, el otro es el comando más el valor.
  • @AlexanderMills, return regresa de la función, exit sale de todo el caparazón. Es ‘ exactamente igual que en, digamos C con return frente a exit(n), o return frente a sys.exit() en Python.

Respuesta

Solo agregaré algunas notas de precaución a las respuestas ya proporcionadas:

  • Aunque return tiene un significado muy especial para el shell, desde el punto de vista de la sintaxis, es un comando incorporado del shell y una declaración de retorno se analiza como cualquier otro comando simple. Eso significa que, como en el argumento de cualquier otro comando, $? cuando no se cita, estaría sujeto a split + glob

    Por lo tanto, debe citar $? para evitarlo:

    return "$?" 
  • return normalmente no «acepta ninguna opción (ksh93» s acepta las --help, --man, --author … aunque). El único argumento que espera (opcional) es el código de retorno. El rango de códigos de retorno aceptados varía de capa a capa, y si cualquier valor fuera de 0..255 se refleja correctamente en

también varía de un shell a otro. Consulte ¿Código de salida predeterminado cuando se termina el proceso? para obtener detalles al respecto.

La mayoría de las shells aceptan números negativos (después de todo, el argumento pasado a la llamada del sistema _exit() / exitgroup() es una int, por lo que los valores abarcan al menos – 2 31 a 2 31 -1, por lo que solo tiene sentido que los shells acepten el mismo rango para sus funciones).

La mayoría de los shells usan waitpid() y co. API para recuperar ese estado de salida; sin embargo, en cuyo caso, se trunca a un número entre 0 y 255 cuando se almacena en $?. Aunque se invoca una función no implica generar un proceso y usó waitpid() para recuperar su estado de salida ya que todo se hace en el mismo proceso, muchos shells también imitan que waitpid() comportamiento al invocar funciones. Lo que significa que incluso si llamas a return con un valor negativo, $? contendrá un número positivo.

Ahora, entre los shells cuyo return acepta números negativos (ksh88, ksh93, bash, zsh, pdksh y derivados distintos de mksh, yash), hay algunos ( pdksh y yash), que deben escribirse como return -- -123, de lo contrario, -123 se toma como tres -1, -2, -3 opciones no válidas.

Como pdksh y su rivatives (como OpenBSD sh o posh) conservan el número negativo en $?, eso significa que hacer return "$?" fallaría cuando $? contiene un número negativo (lo que sucedería cuando el último comando de ejecución fuera una función que devolviera un número negativo ).

Entonces return -- "$?" sería mejor en esos shells. Sin embargo, tenga en cuenta que, si bien es compatible con la mayoría de los shells, esa sintaxis no es POSIX y, en la práctica, no es compatible con mksh y derivados de ash.

Entonces, para resumir, shells basados en pdksh, puede usar números negativos en los argumentos de las funciones, pero si lo hace, return "$@" no funcionará. En otros shells, return "$@" funcionará y debe evitar el uso de números negativos (o números fuera de 0..255) como argumentos para return.

  • En todos los shells que conozco, llamar a return desde el interior de un subshell que se ejecuta dentro de una función hará que el subshell salga (con el estado de salida proporcionado si lo hay o el del último comando ejecutar), pero de otra manera no causará un retorno de la función (para mí, no está claro si POSIX le brinda esa garantía, algunos argumentan que exit debe usarse en lugar de subcapas de salida funciones internas). Por ejemplo

    f() { (return 3) echo "still inside f. Exit status: $?" } f echo "f exit status: $?" 

    generará:

    still inside f. Exit status: 3 f exit status: 0 
  • Respuesta

    Sí, el valor de retorno implícito de una función es el estado de salida de la última ejecutada comando. Eso también es cierto en cualquier punto de cualquier script de shell. En cualquier punto de la secuencia de ejecución del script, el estado de salida actual es el estado de salida del último comando ejecutado. Incluso comando ejecutado como parte de una asignación de variable: var=$(exit 34). La diferencia con las funciones es que una función podría cambiar el estado de salida al final de la ejecución de la función.

    La forma alternativa de cambiar el «estado de salida actual» es iniciar un sub shell y salir con cualquier estado de salida necesario:

    $ $(exit 34) $ echo "$?" 34 

    Y sí, el estado de salida expansión es necesario citar:

    $ IFS="123" $ $(exit 34) $ echo $? 4 

    Un (exit 34) también funciona.
    Algunos pueden argumentar que una construcción más robusta debería ser $(return 34), y que una salida debería «salir» del script que se está ejecutando. Pero $(return 34) no funciona con ninguna versión de bash. Por lo tanto, no es portátil.

    La forma más segura de establecer un estado de salida es usarlo ya que fue diseñado para funcionar, definir y return desde una función :

    exitstatus(){ return "${1:-"$?"}"; } 

    Entonces, al final de una función. es exactamente equivalente a no tener nada o return o return "$?". El final de una función no tiene por qué significar la «última línea de código de una función».

    #!/bin/sh exitstatus(){ a="${1:-"$?"}"; return "$a"; } gmx(){ if [ "$1" = "one" ]; then printf "foo "; exitstatus 78 return "$?" elif [ "$1" = "two" ]; then printf "baz "; exitstatus 89 return else printf "baz "; exitstatus 90 fi } 

    Se imprimirá:

    $ ./script foo 78 baz 89 baz 90 

    El único uso práctico de "$?" es imprimir su valor: echo "$?" o almacenar en una variable (ya que es un valor efímero y cambia con cada comando ejecutado): exitstatus=$? (recuerde citar la variable en comandos como export EXITSTATUS="$?".

    En el comando return, el rango válido de valores es generalmente de 0 a 255, pero entienda que los valores de 126 + n son utilizados por algunos shells para señalar un estado de salida especial, por lo que la recomendación general es utilizar 0-125.

    Deja una respuesta

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *