Puedo definir bash
funciones usando u omitiendo la function
palabra clave. ¿Hay alguna diferencia?
#!/bin/bash
function foo() {
echo "foo"
}
bar() {
echo "bar"
}
foo
bar
Ambas llamadas a funciones foo
tienen bar
éxito y no veo ninguna diferencia. Entonces me pregunto si es solo para mejorar la legibilidad o hay algo que me falta...
Por cierto, en otros shells como dash
( /bin/sh
tiene un enlace simbólico dash
en Debian/ubuntu), falla al usar la function
palabra clave.
Respuesta1
La razón por la que existen dos sintaxis diferentes es histórica. La function
palabra clave vino deksh. La sintaxis inspirada en C ()
provino delconcha de bourne.POSIXestandariza sólo la foo ()
sintaxis de Bourne. Bash y zsh admiten ambos, así como el híbrido function foo () { … }
. Excepto en ATT ksh, la función resultante es exactamente la misma.
Tenga cuidado con un problema con la ()
sintaxis: el nombre de la función está sujeto a expansión de alias.
alias f=g
f () { echo foo; }
type f # f is an alias for g
type g # g is a shell function
f # alias f → function g → print foo
\f # no alias lookup → f: not found
g # function g
En ATT ksh (pero no en pdksh y sus descendientes como mksh), existen algunas diferencias entre las funciones definidas por function
y las funciones definidas con la sintaxis Bourne/POSIX. En las funciones definidas por function
, la typeset
palabra clave declara una variable local: una vez que la función sale, el valor de la variable se restablece al que tenía antes de ingresar a la función. Con la sintaxis clásica, las variables tienen un alcance global, ya sea que las uses typeset
o no.
$ ksh -c 'a=global; f () { typeset a=local; }; f; echo $a'
local
$ ksh -c 'a=global; function f { typeset a=local; }; f; echo $a'
global
Otra diferencia en ksh es que las funciones definidas con la function
palabra clave tienen su propio contexto de captura. Las trampas definidas fuera de la función se ignoran mientras se ejecuta la función, y los errores fatales dentro de la función salen solo de la función y no de todo el script. Además, $0
es el nombre de la función en una función definida por function
pero el nombre del script en una función definida con ()
.
Pdksh no emula ATT ksh. En pdksh, typeset
crea variables de ámbito local independientemente de la función y no hay trampas locales (aunque su uso function
supone algunas diferencias menores; consulte la página de manual para obtener más detalles).
Bash y zsh introdujeron la function
palabra clave para compatibilidad con ksh. Sin embargo, en estos shells function foo { … }
y foo () { … }
son estrictamente idénticos, al igual que las extensiones bash y zsh function foo () { … }
(excepto por la posible expansión del alias al analizar la definición, como se explicó anteriormente). La typeset
palabra clave siempre declara variables locales (excepto con, -g
por supuesto), y las trampas no son locales (puede obtener trampas locales en zsh configurando la local_traps
opción).
Respuesta2
No hay diferencia AFAIK, aparte del hecho de que la segunda versión es más portátil.
Respuesta3
foo() any-command
es la sintaxis de Bourne compatible con cualquier shell similar a Bourne pero bash
,yash
y versiones recientes de posh
(que solo admiten comandos compuestos). (Sin embargo, las implementaciones de Bourne Shell y AT&T ksh
no son compatibles foo() any-command > redirections
a menos que any-command
sea un comando compuesto).
foo() any-compound-command
(ejemplos de comandos compuestos: { cmd; }
, for i do echo "$i"; done
, (cmd)
... siendo el más utilizado { ...; }
)
es la sintaxis POSIX compatible con cualquier shell tipo Bourne y la que generalmente desea utilizar.
function foo { ...; }
es la sintaxis del shell Korn, que es anterior a la sintaxis de Bourne. Utilice este solo si escribe específicamente para la implementación de AT&T del shell Korn y necesita el tratamiento específico que recibe allí. Esa sintaxis no es POSIX, pero es compatible con bash
, yash
y zsh
por compatibilidad con el shell Korn, aunque esos shells (y las pdksh
variantes basadas en -del shell Korn) no la tratan de manera diferente a la sintaxis estándar.
function foo () { ...; }
es la sintaxis deNoconcha yNo debería ser usado. Resulta que solo es compatible por accidente con bash
, y las variantes basadas del shell Korn. Por cierto, también es la sintaxis de la función.yash
zsh
pdksh
awk
Si seguimos bajando por la lista esotérica,
function foo() other-compound-command
(como function foo() (subshell)
o function foo() for i do; ... done
) es aún peor. Es compatible con bash
, yash
y zsh
, pero no con ksh, ni siquiera con las pdksh
variantes basadas en -.
Mientras:
function foo() simple command
sólo es compatible con zsh
.
foo bar() any-command
O incluso:
$function_list() any-command
Definir varias funciones a la vez sólo es compatible conzsh
function { body; } args
() any-compound-command args
cuales sonfunción anónimalas invocaciones, solo son compatibles con zsh
también.
Respuesta4
Varios otros ya han respondido correctamente, pero aquí está mi sinopsis concisa:
La segunda versión es portátil y probablemente funcione con muchos shells estándar (particularmente POSIX).
La primera versión funcionará solo con bash, pero puede omitir los paréntesis que siguen al nombre de la función.
De lo contrario, representan entidades idénticas después de que bash las interprete.