разница между "function foo() {}" и "foo() {}"

разница между "function foo() {}" и "foo() {}"

Я могу определять 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.

Связанный контент