web-dev-qa-db-ja.com

「関数foo(){}」と「foo(){}」の違い

bashキーワードを使用するか省略して、function関数を定義できます。違いはありますか?

#!/bin/bash

function foo() {
  echo "foo"
}

bar() {
  echo "bar"
}

foo

bar

関数foobarの両方の呼び出しが成功し、違いがわかりません。だから、読みやすさを向上させるためだけなのか、それとも私が見逃しているものがあるのか​​...

ところでdash/bin/shはdebian/ubuntuのdashにシンボリックリンクされています)functionキーワードを使用すると失敗します。

103

2つ目のバージョンの方が移植性が高いという事実を除けば、AFAIKに違いはありません。

44
schaiba

functionキーワードは ksh で導入されました。従来の Bourne Shell にはfoo ()構文しかありませんでした [〜#〜] posix [〜#〜]foo ()のみを標準化します構文。

ATT ksh(pdkshではない)では、functionで定義された関数と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のもう1つの違いは、functionキーワードで定義された関数が独自のトラップコンテキストを持つことです。関数の外部で定義されたトラップは、関数の実行中は無視され、関数内の致命的なエラーは、関数全体からではなく関数からのみ終了します。また、$0functionで定義された関数の関数名ですが、()で定義された関数のスクリプト名です。

PdkshはATT kshをエミュレートしません。 pdkshでは、typesetは関数に関係なくローカルスコープの変数を作成し、ローカルトラップはありません(functionを使用すると多少の違いが生じます。詳細はmanページを参照してください)。

Bashとzshは、kshとの互換性のためにfunctionキーワードを導入しました。ただし、これらのシェルでは、function foo { … }foo () { … }は厳密に同一であり、bashおよびzsh拡張function foo () { … }も同様です。 typesetキーワードは常にローカル変数を宣言し(もちろん-gを除く)、トラップはローカルではありません(local_trapsオプションを設定することにより、zshでローカルトラップを取得できます)。

_foo() any-command
_

bashyash 、および最近のバージョンのposh(複合コマンドのみをサポート)を除く、BourneのようなシェルでサポートされるBourne構文です。 (ただし、Bourne ShellおよびkshのAT&T実装は、_any-command_が複合コマンドでない限り、foo() any-command > redirectionsをサポートしていません)。

_foo() any-compound-command
_

(複合コマンドの例:_{ cmd; }_、_for i do echo "$i"; done_、_(cmd)_...最も一般的に使用されるのは_{ ...; }_)

bourneのようなシェルでサポートされているPOSIX構文であり、一般的に使用したいものです。

_function foo { ...; }
_

bourne構文よりも古いKornシェル構文です。 Korn ShellのAT&T実装用に特別に記述し、そこで受けられる特定の扱いが必要な場合にのみ、これを使用してください。その構文はPOSIXではありませんが、bashyashzshでサポートされています。これらのシェル(およびpdkshベースKornシェルのバリアント)は、標準の構文との違いはありません。

_function foo () { ...; }
_

noShellおよび 使用しないでください の構文です。それは偶然に偶然にbashyashzshおよびKornシェルのpdkshベースのバリアントによってのみサポートされます。ちなみに、これはawk関数の構文でもあります。

難解なリストを続けていくと、

_function foo() other-compound-command
_

function foo() (subshell)またはfunction foo() for i do; ... doneのような)はさらに悪いです。 bashyashおよびzshではサポートされていますが、pdkshベースのバリアントであってもkshではサポートされていません。

その間:

_function foo() simple command
_

zshでのみサポートされています。

35

意味的には、これら2つの形式はBashでは同等です。

Manページから:

シェル関数は次のように宣言されています。

name () compound-command [redirection]
function name [()] compound-command [redirection]

これは、nameという名前の関数を定義します。予約語functionはオプションです。 function予約語が指定されている場合、括弧はオプションです。

編集:私はこの質問がposixとタグ付けされていることに気づきました。 POSIX shでは、functionキーワードは使用されません(予約されています)。

22
depquid

他のいくつかは今までに正しく答えましたが、ここに私の簡潔な概要があります:

2番目のバージョンは移植可能であり、多くの標準(特にPOSIX)シェルで動作する可能性があります。

最初のバージョンはbashでのみ機能しますが、関数名に続く括弧は省略できます。

それ以外の場合、bashが解釈した後、それらは同一のエンティティを表します。

3
destenson