我可以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 語法定義的函數之間存在一些差異。在由 定義的函數中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
確實會產生一些細微的差異 - 有關詳細信息,請參閱手冊頁)。
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 語法,但是bash
,yash
和最新版本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,但受bash
、yash
和zsh
Korn shell 支持,儘管這些 shell(以及pdksh
Korn shell 的基於 - 的變體)不會將其視為與標準語法有任何不同。
function foo () { ...; }
的語法是不殼和不應該使用。它只是偶然被bash
、yash
和Korn shell 的基礎變體zsh
支持。pdksh
順便說一句,這也是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
as well。
答案4
到目前為止,其他幾個人已經正確回答了,但這是我的簡要概要:
第二個版本是可移植的,並且可能與許多標準(特別是 POSIX)shell 一起使用。
第一個版本僅適用於 bash,但您可以省略函數名稱後面的括號。
否則,在 bash 解釋它們之後,它們代表相同的實體。