Я могу определять bash
функции, используя или опуская function
ключевое слово. Есть ли разница?
#!/bin/bash
function foo() {
echo "foo"
}
bar() {
echo "bar"
}
foo
bar
Оба вызова функций foo
и bar
успешны, и я не вижу никакой разницы. Поэтому мне интересно, это просто для улучшения читабельности или я что-то упускаю...
Кстати, в других оболочках, например dash
( /bin/sh
на которую есть символическая ссылка dash
в Debian/Ubuntu), при использовании ключевого слова происходит сбой function
.
решение1
Причина существования двух разных синтаксисов историческая. function
Ключевое слово пришло изкшСинтаксис , вдохновленный языком C, ()
пришел изоболочка Борна.POSIXстандартизирует только синтаксис Bourne foo ()
. Bash и zsh поддерживают оба, а также гибрид function foo () { … }
. За исключением ATT ksh, результирующая функция абсолютно одинакова.
Остерегайтесь подводных камней в ()
синтаксисе: имя функции может быть расширено псевдонимами.
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
В ATT ksh (но не pdksh и его потомках, таких как mksh) есть несколько различий между функциями, определенными с помощью function
синтаксиса Bourne/POSIX, и функциями, определенными с помощью синтаксиса Bourne/POSIX. В функциях, определенных с помощью function
, typeset
ключевое слово объявляет локальную переменную: после выхода из функции значение переменной сбрасывается до того, что было до входа в функцию. С классическим синтаксисом переменные имеют глобальную область видимости, используете вы ее typeset
или нет.
$ 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
Другое отличие в ksh заключается в том, что функции, определенные с function
ключевым словом , имеют свой собственный контекст ловушек. Ловушки, определенные вне функции, игнорируются при выполнении функции, а фатальные ошибки внутри функции приводят к выходу только из функции, а не из всего скрипта. Кроме того, $0
является ли имя функции в функции, определенной с помощью , function
а имя скрипта в функции, определенной с помощью ()
.
Pdksh не эмулирует ATT ksh. В pdksh typeset
создает локально-областные переменные независимо от функции, и нет локальных ловушек (хотя использование function
вносит некоторые незначительные изменения — подробности см. на странице man).
Bash и zsh ввели function
ключевое слово для совместимости с ksh. Однако в этих оболочках function foo { … }
и foo () { … }
строго идентичны, как и расширение bash и zsh function foo () { … }
(за исключением потенциального расширения псевдонима при разборе определения, как объяснено выше). typeset
Ключевое слово всегда объявляет локальные переменные (кроме, конечно, with -g
), а ловушки не являются локальными (вы можете получить локальные ловушки в zsh, установив опцию local_traps
).
решение2
Насколько мне известно, разницы нет, за исключением того, что вторая версия более портативна.
решение3
foo() any-command
поддерживается ли синтаксис Bourne любой оболочкой, подобной Bourne, но bash
,yash
и последние версии posh
(которые поддерживают только составные команды). (хотя оболочка Bourne и реализации AT&T ksh
не поддерживают foo() any-command > redirections
, если any-command
только это не составная команда).
foo() any-compound-command
(примеры составных команд: { cmd; }
, for i do echo "$i"; done
, (cmd)
... наиболее часто используемая из них { ...; }
)
— это синтаксис POSIX, поддерживаемый любой оболочкой типа Bourne, и именно его вы обычно хотите использовать.
function foo { ...; }
- это синтаксис оболочки Korn, который предшествовал синтаксису Bourne. Используйте его только в том случае, если пишете специально для реализации оболочки Korn от AT&T и нуждаетесь в особой обработке, которую она там получает. Этот синтаксис не является POSIX, но поддерживается bash
, yash
и zsh
для совместимости с оболочкой Korn, хотя эти оболочки (и pdksh
основанные на -варианты оболочки Korn) не обрабатывают его иначе, чем стандартный синтаксис.
function foo () { ...; }
это синтаксиснетоболочка ине следует использовать. Он поддерживается случайно только bash
, yash
, zsh
и pdksh
основанными на них вариантами оболочки Korn. Кстати, это также awk
синтаксис функции.
Если мы продолжим идти по эзотерическому списку,
function foo() other-compound-command
(как function foo() (subshell)
или function foo() for i do; ... done
) еще хуже. Поддерживается bash
, yash
и zsh
, но не ksh, даже pdksh
основанными на -вариантами.
Пока:
function foo() simple command
поддерживается только zsh
.
foo bar() any-command
Или даже:
$function_list() any-command
Определение нескольких функций одновременно поддерживается толькоzsh
function { body; } args
() any-compound-command args
Которыеанонимная функциявызовы, поддерживаются только zsh
также.
решение4
Несколько других уже ответили правильно, но вот мой краткий обзор:
Вторая версия является переносимой и, скорее всего, будет работать со многими стандартными (в частности, POSIX) оболочками.
Первая версия будет работать только с bash, но вы можете опустить скобки после имени функции.
В противном случае они представляют собой идентичные сущности после их интерпретации bash.