“function foo() {}”和“foo() {}”之間的區別

“function foo() {}”和“foo() {}”之間的區別

我可以bash使用或省略function關鍵字來定義函數。有什麼區別嗎?

#!/bin/bash

function foo() {
  echo "foo"
}

bar() {
  echo "bar"
}

foo

bar

對函數的呼叫都foo成功bar了,我看不出有什麼差別。所以我想知道這是否只是為了提高可讀性,或者我缺少什麼...

順便說一句,在其他 shell 中,例如dash(在 debian/ubuntu 中/bin/sh符號連結dash),使用關鍵字時會失敗function

答案1

存在兩種不同語法的原因是歷史性的。關鍵字function來自克什。受 C 啟發的()語法來自伯恩外殼POSIX僅標準化 Bournefoo ()語法。 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

function在 ATT ksh(但不是 pdksh 及其後代,例如 mksh)中,由 Bourne/POSIX 語法定義的函數和以 Bourne/POSIX 語法定義的函數之間存在一些差異。在由 定義的函數中functiontypeset關鍵字會宣告一個局部變數:一旦函數退出,變數的值將重設為進入該函數之前的值。使用經典語法,無論您使用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確實會產生一些細微的差異 - 有關詳細信息,請參閱手冊頁)。

Bash 和 zsh 引入了function與 ksh 相容的關鍵字。然而,在這些 shell 中function foo { … }, 和foo () { … }是嚴格相同的,bash 和 zsh 擴展也是如此function foo () { … }(解析定義時潛在的別名擴展除外,如上所述)。關鍵字typeset總是聲明局部變數(-g當然除了 with ),陷阱不是局部的(你可以透過設定選項在 zsh 中獲得局部陷阱local_traps)。

答案2

據我所知,除了第二個版本更便攜之外,沒有什麼區別。

答案3

foo() any-command

是任何類似 Bourne 的 shell 支援的 Bourne 語法,但是bashyash和最新版本posh(僅支援複合命令)。 (Bourne shell 和 AT&T 實作ksh不支援foo() any-command > redirections除非any-command是複合命令)。

foo() any-compound-command

(複合指令的範例:{ cmd; }, for i do echo "$i"; done, (cmd)... 最常用的是{ ...; }

是任何類似 Bourne 的 shell 都支援的 POSIX 語法,也是您通常想要使用的語法。

function foo { ...; }

是 Korn shell 語法,它早於 Bourne 語法。僅當專門為 Korn shell 的 AT&T 實作編寫並且需要它在那裡接受的特定處理時才使用此選項。該語法不是 POSIX,但受bashyashzshKorn shell 支持,儘管這些 shell(以及pdkshKorn shell 的基於 - 的變體)不會將其視為與標準語法有任何不同。

function foo () { ...; }

的語法是殼和不應該使用。它只是偶然被bashyash和Korn shell 的基礎變體zsh支持。pdksh順便說一句,這也是awk函數語法。

如果我們繼續深入深奧的清單,

function foo() other-compound-command

(如function foo() (subshell)function foo() for i do; ... done)更糟。bashyash和都支援它zsh,但 ksh 不支援它,甚至pdksh基於 - 的變體也是如此。

儘管:

function foo() simple command

僅支援zsh.

foo bar() any-command

甚至:

$function_list() any-command

僅支援一次定義多個函數zsh

function { body; } args
() any-compound-command args

哪個是匿名函數調用,僅支援zshas well。

答案4

到目前為止,其他幾個人已經正確回答了,但這是我的簡要概要:

第二個版本是可移植的,並且可能與許多標準(特別是 POSIX)shell 一起使用。

第一個版本僅適用於 bash,但您可以省略函數名稱後面的括號。

否則,在 bash 解釋它們之後,它們代表相同的實體。

相關內容