Bash

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

  • January 21, 2022

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

#!/bin/bash

function foo() {
 echo "foo"
}

bar() {
 echo "bar"
}

foo

bar

兩個函式呼叫都foo成功了bar,我看不出有什麼區別。所以我想知道這是否只是為了提高可讀性,還是我缺少一些東西……

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

除了第二個版本更便攜之外,AFAIK 沒有任何區別。

有兩種不同語法的原因是歷史原因。function關鍵字來自ksh。受 C 啟發的()語法來自Bourne shellPOSIX僅標準化 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

在 ATT ksh(但不是 pdksh 及其後代,例如 mksh)中,由functionBourne/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無論函式如何,都會創建局部範圍的變數,並且沒有局部陷阱(儘管 usingfunction確實會產生一些細微的差異 - 有關詳細資訊,請參閱手冊頁)。

Bash 和 zsh 引入了function與 ksh 兼容的關鍵字。然而,在這些 shell中function foo { … }foo () { … }它們是完全相同的,bash 和 zsh 擴展也是如此function foo () { … }(解析定義時可能存在的別名擴展除外,如上所述)。typeset關鍵字總是聲明局部變數(當然with除外)-g,並且陷阱不是本地的(可以通過設置local_traps選項在zsh中獲取局部陷阱)。

引用自:https://unix.stackexchange.com/questions/73750