parameter - Valor de retorno en una función Bash
def function bash (9)
Estoy trabajando con un script de bash y quiero ejecutar una función para imprimir un valor de retorno:
function fun1(){
return 34
}
function fun2(){
local res=$(fun1)
echo $res
}
Cuando ejecuto fun2
, no se imprime "34". ¿Por qué es este el caso?
Aunque bash tiene una declaración de return
, lo único que puede especificar es el estado de exit
propio de la función (un valor entre 0
y 255
, 0 significa "éxito"). Así que el return
no es lo que quieres.
Es posible que desee convertir su declaración de return
en una declaración de echo
; de esa manera, la salida de su función podría capturarse utilizando llaves $()
, que parece ser exactamente lo que desea.
Aquí hay un ejemplo:
function fun1(){
echo 34
}
function fun2(){
local res=$(fun1)
echo $res
}
Otra forma de obtener el valor de retorno (si solo desea devolver un número entero de 0-255) es $?
.
function fun1(){
return 34
}
function fun2(){
fun1
local res=$?
echo $res
}
Además, tenga en cuenta que puede usar el valor de retorno para usar la lógica booleana como fun1 || fun2
fun1 || fun2
solo ejecutará fun2
si fun1
devuelve un valor de 0
. El valor de retorno predeterminado es el valor de salida de la última instrucción ejecutada dentro de la función.
Como un complemento a las excelentes publicaciones de otros, aquí hay un artículo que resume estas técnicas:
- establecer una variable global
- establece una variable global, cuyo nombre pasaste a la función
- configurar el código de retorno (y recogerlo con $?)
- ''echo'' algunos datos (y recójalos con MYVAR = $ (mi función))
El problema con otras respuestas es que usan un global, que puede sobrescribirse cuando varias funciones están en una cadena de llamadas, o eco, lo que significa que su función no puede generar información de diagnóstico (olvidará que su función hace esto y el "resultado", es decir, el valor de retorno, contendrá más información de la que espera el autor de la llamada, lo que provocará un error extraño), o eval, que es demasiado pesado e intrépido.
La forma correcta de hacer esto es poner las cosas de nivel superior en una función y usar una regla local de alcance dinámico de bash. Ejemplo:
func1()
{
ret_val=hi
}
func2()
{
ret_val=bye
}
func3()
{
local ret_val=nothing
echo $ret_val
func1
echo $ret_val
func2
echo $ret_val
}
func3
Esto produce
nothing
hi
bye
¡El alcance dinámico significa que ret_val apunta a un objeto diferente dependiendo de la persona que llama! Esto es diferente del alcance léxico, que es el que utilizan la mayoría de los lenguajes de programación. Esta es en realidad una característica documentada , simplemente fácil de perder, y no muy bien explicada, aquí está la documentación (el énfasis es mío):
Las variables locales a la función se pueden declarar con la función interna local. Estas variables son visibles solo para la función y los comandos que invoca .
Para alguien con un fondo C / C ++ / Python / Java / C # / javascript, este es probablemente el mayor obstáculo: las funciones en bash no son funciones, son comandos y se comportan como tales: pueden salir a stdout / stderr, pueden Tubo de entrada / salida, pueden devolver un código de salida. Básicamente, no hay diferencia entre definir un comando en una secuencia de comandos y crear un archivo ejecutable al que se puede llamar desde el comando.
Así que en lugar de escribir tu guión de esta manera:
top-level code
bunch of functions
more top-level code
escríbelo así:
# define your main, containing all top-level code
main()
bunch of functions
# call main
main
donde main () declara ret_val como local y todas las demás funciones devuelven valores a través de ret_val.
Consulte también https://unix.stackexchange.com/questions/282557/scope-of-local-variables-in-shell-functions .
La declaración de return
establece el código de salida de la función, lo mismo que la exit
para todo el script.
El código de salida para el último comando siempre está disponible en $?
variable.
function fun1(){
return 34
}
function fun2(){
local res=$(fun1)
echo $? # <-- Always echos 0 since the ''local'' command passes.
res=$(fun1)
echo $? #<-- Outputs 34
}
Las funciones en Bash no son funciones como en otro lenguaje; En realidad son comandos. Por lo tanto, las funciones se utilizan como si fueran archivos binarios o scripts recuperados de su ruta. Desde la perspectiva de la lógica de tu programa, realmente no debería haber diferencia.
Los comandos de shell están conectados por canalizaciones (también conocidas como secuencias), y no por tipos de datos fundamentales o definidos por el usuario, como en los lenguajes de programación "reales". No existe tal cosa como un valor de retorno para un comando, tal vez principalmente porque no hay una forma real de declararlo. Podría ocurrir en la página del manual o en la salida --help
del comando, pero ambas son solo legibles por humanos y, por lo tanto, están escritas al viento.
Cuando un comando desea obtener una entrada, la lee de su flujo de entrada o de la lista de argumentos. En ambos casos, las cadenas de texto tienen que ser analizadas.
Cuando un comando quiere devolver algo, debe echo
a su flujo de salida. Otra forma a menudo practicada es almacenar el valor de retorno en variables globales dedicadas. Escribir en el flujo de salida es más claro y más flexible, ya que también puede tomar datos binarios. Por ejemplo, puede devolver un BLOB fácilmente:
encrypt() {
gpg -c -o- $1 # encrypt data in filename to stdout (asks for a passphrase)
}
encrypt public.dat > private.dat # write function result to file
Como otros han escrito en este hilo, la persona que llama también puede usar el comando de sustitución $()
para capturar la salida.
Paralelamente, la función "devolvería" el código de salida de gpg
(GnuPG). Piense en el código de salida como un bono que otros idiomas no tienen, o, dependiendo de su temperamento, como un "Schmutzeffekt" de funciones de shell. Este estado es, por convención, 0 en caso de éxito o un número entero en el rango 1-255 para otra cosa. Para dejar esto en claro: return
(como exit
) solo puede tomar un valor de 0-255, y los valores distintos de 0 no son necesariamente errores, como se suele afirmar.
Cuando no proporciona un valor explícito con return
el estado se toma del último comando en una declaración / función / comando Bash y así sucesivamente. Así que siempre hay un estado, y el return
es solo una forma fácil de proporcionarlo.
Me gusta hacer lo siguiente si se ejecuta en un script donde se define la función:
POINTER= # used for function return values
my_function() {
# do stuff
POINTER="my_function_return"
}
my_other_function() {
# do stuff
POINTER="my_other_function_return"
}
my_function
RESULT="$POINTER"
my_other_function
RESULT="$POINTER"
Me gusta esto, porque entonces puedo incluir sentencias de eco en mis funciones si quiero
my_function() {
echo "-> my_function()"
# do stuff
POINTER="my_function_return"
echo "<- my_function. $POINTER"
}
Otra forma de lograr esto es mediante referencias de nombre (requiere Bash 4.3+).
function example {
local -n VAR=$1
VAR=foo
}
example RESULT
echo $RESULT
$(...)
captura el texto enviado a stdout por el comando contenido en. return
no sale a la salida estándar. $?
Contiene el código de resultado del último comando.
fun1 (){
return 34
}
fun2 (){
fun1
local res=$?
echo $res
}
Git Bash en Windows usando matrices para múltiples valores de retorno
CÓDIGO DE BASH:
#!/bin/bash
##A 6-element array used for returning
##values from functions:
declare -a RET_ARR
RET_ARR[0]="A"
RET_ARR[1]="B"
RET_ARR[2]="C"
RET_ARR[3]="D"
RET_ARR[4]="E"
RET_ARR[5]="F"
function FN_MULTIPLE_RETURN_VALUES(){
##give the positional arguments/inputs
##$1 and $2 some sensible names:
local out_dex_1="$1" ##output index
local out_dex_2="$2" ##output index
##Echo for debugging:
echo "running: FN_MULTIPLE_RETURN_VALUES"
##Here: Calculate output values:
local op_var_1="Hello"
local op_var_2="World"
##set the return values:
RET_ARR[ $out_dex_1 ]=$op_var_1
RET_ARR[ $out_dex_2 ]=$op_var_2
}
echo "FN_MULTIPLE_RETURN_VALUES EXAMPLES:"
echo "-------------------------------------------"
fn="FN_MULTIPLE_RETURN_VALUES"
out_dex_a=0
out_dex_b=1
eval $fn $out_dex_a $out_dex_b ##<--Call function
a=${RET_ARR[0]} && echo "RET_ARR[0]: $a "
b=${RET_ARR[1]} && echo "RET_ARR[1]: $b "
echo
##----------------------------------------------##
c="2"
d="3"
FN_MULTIPLE_RETURN_VALUES $c $d ##<--Call function
c_res=${RET_ARR[2]} && echo "RET_ARR[2]: $c_res "
d_res=${RET_ARR[3]} && echo "RET_ARR[3]: $d_res "
echo
##----------------------------------------------##
FN_MULTIPLE_RETURN_VALUES 4 5 ##<---Call function
e=${RET_ARR[4]} && echo "RET_ARR[4]: $e "
f=${RET_ARR[5]} && echo "RET_ARR[5]: $f "
echo
##----------------------------------------------##
read -p "Press Enter To Exit:"
RENDIMIENTO ESPERADO:
FN_MULTIPLE_RETURN_VALUES EXAMPLES:
-------------------------------------------
running: FN_MULTIPLE_RETURN_VALUES
RET_ARR[0]: Hello
RET_ARR[1]: World
running: FN_MULTIPLE_RETURN_VALUES
RET_ARR[2]: Hello
RET_ARR[3]: World
running: FN_MULTIPLE_RETURN_VALUES
RET_ARR[4]: Hello
RET_ARR[5]: World
Press Enter To Exit: