diferencia entre "function foo () {}" y "foo () {}"

96

Puedo definir bashfunciones usando u omitiendo la functionpalabra clave. ¿Hay alguna diferencia?

#!/bin/bash

function foo() {
  echo "foo"
}

bar() {
  echo "bar"
}

foo

bar

Ambas llamadas a funciones fooy baréxito y no puedo ver ninguna diferencia. Así que me pregunto si es solo para mejorar la legibilidad, o si hay algo que me falta ...

Por cierto, en otros shells como dash( /bin/shestá vinculado simbólicamente dashen debian / ubuntu) falla cuando se usa la functionpalabra clave.

Carlos Campderrós
fuente
8
También con o sin el paréntesis: function baz { echo "baz"; }. Ver del bash en el wiki de GreyCat.
manatwork

Respuestas:

42

No hay diferencia AFAIK, aparte del hecho de que la segunda versión es más portátil.

schaiba
fuente
32
Esa es una GRAN diferencia, la portabilidad ... Veo demasiadas respuestas que simplemente NO funcionan en sistemas de producción (más antiguos), y también muchas con opciones que solo funcionan en Linux. Al menos, advierta que esta no es la forma más portátil ... Podría ser francamente peligroso (pedirle a alguien tar cf - /some/thing | ssh user@desthost "cd destinationdir && tar xf - " sin advertirle que primero verifique dos veces si la versión de alquitrán en desthost eliminará el "/" podría conducir a desastres en algunos casos ...). Por ejemplo: si el uso de una function tar { #a safe tar with safety checks ... }y shlo ignora, ...
Olivier Dulac
1
@OlivierDulac Agregaría que los scripts que asumen que shreconocen la functionpalabra clave y, en general, que asumen características comunes pero no estándar que les gustan kshy bashofrecen, a menudo tampoco funcionarán en sistemas de producción más nuevos , incluso si funcionaban en versiones anteriores de El mismo sistema operativo. bashtodavía se ofrece shen muchos sistemas GNU / Linux, pero algunas distribuciones populares han pasado a tener shcomo enlace simbólico a dash(Debian Almquist SHell) para mejorar el rendimiento. Esto incluye Debian y Ubuntu .
Eliah Kagan
2
Sin explicar cómo es exactamente "más portátil", la respuesta no es útil.
ivan_pozdeev
La portabilidad no es un argumento hoy en día donde la industria está utilizando bash o un shell equivalente en> 99.9% de todos los entornos. Se reduce a la legibilidad y hay dos lados: algunas personas dicen que la "función" lo hace obvio, las personas que lo aprendieron de los estándares posix u otros shells dirán que los frenos son el estilo más obvio. Al final, elija uno dentro de su grupo o empresa y manténgalo.
Hubert Grzeskowiak
93

La functionpalabra clave se introdujo en ksh . El shell Bourne tradicional solo tenía la foo ()sintaxis, y POSIX estandariza solo la foo ()sintaxis.

En ATT ksh (pero no pdksh), existen algunas diferencias entre las funciones definidas por functiony las funciones definidas con la sintaxis Bourne / POSIX. En las funciones definidas por function, la typesetpalabra clave declara una variable local: una vez que la función sale, el valor de la variable se restablece a lo que era antes de ingresar a la función. Con la sintaxis clásica, las variables tienen un alcance global, se use typeseto 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 functionpalabra clave tienen su propio contexto de trampa. Las trampas definidas fuera de la función se ignoran al ejecutar la función, y los errores fatales dentro de la función salen solo de la función y no del script completo. Además, $0es el nombre de la función en una función definida por functionpero el nombre del script en una función definida con ().

Pdksh no emula ATT ksh. En pdksh, typesetcrea variables de ámbito local independientemente de la función, y no hay trampas locales (aunque el uso functionhace algunas diferencias menores; consulte la página del manual para obtener más detalles).

Bash y zsh introdujeron la functionpalabra clave para compatibilidad con ksh. Sin embargo en estos shells function foo { … }y foo () { … }son estrictamente idénticos, como es la extensión bash y zsh function foo () { … }. La typesetpalabra clave siempre declara variables locales (excepto con, -gpor supuesto), y las trampas no son locales (puede obtener trampas locales en zsh configurando la local_trapsopción).

Gilles
fuente
8
Cabe señalar que el soporte de funciones se agregó al shell Korn antes de que el shell Bourne introdujera su foo() commandsintaxis, y la sintaxis de Bourne se agregó más tarde al shell Korn por compatibilidad.
Stéphane Chazelas
2
¿Es correcto que se function { ... }; f;omita fdespués de la functionpalabra clave?
Ruslan
32
foo() any-command

es la sintaxis Bourne apoyado por cualquier shell Bourne-como pero bash, yashy las versiones recientes de posh(que sólo apoyar comandos compuestos). (Las implementaciones de Bourne shell y AT&T kshno son compatibles a foo() any-command > redirectionsmenos que any-commandsea ​​un comando compuesto).

foo() any-compound-command

(ejemplos de compuesto comandos: { cmd; }, for i do echo "$i"; done, (cmd)... el ser más utilizada { ...; })

es la sintaxis POSIX compatible con cualquier shell similar a Bourne y la que generalmente desea usar.

function foo { ...; }

es la sintaxis de shell Korn, que es anterior a la sintaxis de Bourne. Use 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, yashy zshpara compatibilidad con el shell Korn, aunque esos shells (y las pdkshvariantes basadas en el shell Korn) no lo tratan de manera diferente a la sintaxis estándar.

function foo () { ...; }

es la sintaxis de no shell y no debe usarse . Esto sólo ocurre con el apoyo de accidente por bash, yash, zshy las pdkshvariantes basadas del shell Korn. Por cierto, también es la awksintaxis de la función.

Si continuamos bajando por la lista esotérica,

function foo() other-compound-command

(me gusta function foo() (subshell)o function foo() for i do; ... done) es aún peor. Es compatible con bash, yashy zsh, pero no ksh, incluso las pdkshvariantes basadas.

Mientras:

function foo() simple command

solo es compatible con zsh.

Stéphane Chazelas
fuente
1
La sintaxis que incluye tanto la functionpalabra clave como los paréntesis se documenta en Bash. El manual de Bash 4.2 y posterior dice que las funciones son declaradas por la sintaxis name () compound-command [ redirections ]o function name [()] compound-command [ redirections ]. En Bash 4.1.11 hasta al menos 3.0-beta que era solo la línea simple [ function ] name () compound-command [redirection]que erróneamente no cubre la sintaxis que incluye la functionpalabra clave pero no paréntesis, pero aún cubre la sintaxis que incluye tanto la functionpalabra clave como los paréntesis.
nisetama
@nise, el punto es que bashreconoce function foo {además foo() {de la compatibilidad con el shell Korn (y siempre lo ha hecho) para que pueda interpretar los scripts escritos para el shell Korn. También es compatible function foo () {, pero no hay una buena razón para usarlo.
Stéphane Chazelas
2
@ StéphaneChazelas Bueno, yo diría que hay una buena razón para usar function f() {. Es decir, en términos de legibilidad, será reconocido como una función por cualquiera que sepa inglés y cualquiera que sepa C, en comparación con solo uno de estos conjuntos.
DepressedDaniel
2
Debería ser la respuesta aceptada. Realmente importanteYou should never combine the keyword function with the parentheses () when defining a function.
4wk_
Bienvenido a 2019, donde solo hay un estándar de facto de la industria para los scripts de automatización de Linux / Unix; el único intérprete que está instalado prácticamente en todas partes (dejando de lado los entornos exóticos): bash. Escriba su código con todas las funciones de bash, use el shebang y estará bien. El argumento de compatibilidad es nulo.
Hubert Grzeskowiak
22

Semánticamente, esas dos formas son equivalentes en Bash.

Desde la página del manual:

Las funciones de shell se declaran de la siguiente manera:

name () compound-command [redirection]
function name [()] compound-command [redirection]

Esto define una función llamada name. La función de palabra reservada es opcional. Si se proporciona la palabra reservada de función , los paréntesis son opcionales.

EDITAR: Acabo de notar que esta pregunta está etiquetada posix. En POSIX sh, la functionpalabra clave no se usa (aunque está reservada).

depquid
fuente
3

Varios otros han respondido correctamente por ahora, pero aquí está mi sinopsis concisa:

La segunda versión es portátil y es probable que 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 interpreta.

destenson
fuente
en realidad, la primera versión no tiene sentido excepto limitarla como sintaxis aceptable a algunos shells. cuando se incluye el () y la functionpalabra clave de la cáscara se comporta como si usted acaba de hacer foo(){ ...; }de todos modos, excepto, por supuesto, de una concha en la que es una sintaxis no válida. y así debe hacerlo function foo { ...; }si es necesario, o de lo foo(){ ...; }contrario.
mikeserv