「function foo(){}」と「foo(){}」の違い

「function foo(){}」と「foo(){}」の違い

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

#!/bin/bash

function foo() {
  echo "foo"
}

bar() {
  echo "bar"
}

foo

bar

関数への呼び出しはすべてfoo成功し、bar違いは見られません。それで、これが単に可読性のためであるのか、それとも何か抜けたのかどうか疑問に思います。

ただし、他のシェル(dashdebian / ubuntuの/bin/shシンボリックリンクなどdash)では、キーワードを使用すると失敗しますfunction

答え1

2つの異なる構文がある理由は歴史的です。キーワードfunctionのソースケシ。 C()に触発された構文ボンシェルPOSIXBournefoo ()構文のみが標準化されています。 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

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

Pdksh は ATT ksh をエミュレートしません。 pdkshではtypeset機能に関係なくローカルスコープ変数が生成され、ローカルトラップはありません(使用によってはわずかなfunction違いがありますが、詳細についてはマニュアルページを参照)。

Bashとzshはfunctionksh互換キーワードを導入します。ただし、これらのシェルでは bash および zsh 拡張と同様に厳密に同じですfunction foo { … }(上記のように定義を解析する際の潜在的なエイリアス拡張を除く)。キーワードは常にローカル変数を宣言します(もちろん除外)、トラップはローカルではありません(オプションを設定してzshからローカルトラップを取得できます)。foo () { … }function foo () { … }typeset-glocal_traps

答え2

私が知っている限り、2番目のバージョンは移植性が良いということ以外に違いはありません。

答え3

foo() any-command

Bourneに似たシェルでサポートされているBourne構文ですがbashyashと最新バージョンposh(複合コマンドのみサポートkshfoo() any-command > redirectionsany-command

foo() any-compound-command

(複合コマンドの例:{ cmd; }、、、for i do echo "$i"; done...(cmd)最も一般的に使用されます{ ...; }

Bourneに似たシェルでサポートされているPOSIX構文で、一般的に使用したい構文です。

function foo { ...; }

Bourne 構文の前にある Korn シェル構文です。 Korn シェルの AT&T 実装用に特別に作成し、そこで受け取る特定の処理が必要な場合にのみ、このオプションを使用してください。この構文はPOSIXではありませんが、Kornシェルでサポートされていますbashyashただしzsh、これらのシェル(およびpdkshKornシェルの - ベースのバリエーション)はこれを標準構文とは異なって扱いません。

function foo () { ...; }

構文は次のとおりです。いいえシェルと使用しないでください。これはbash、およびKornシェルyashの基本的なバリエーションでのみ偶然サポートされますzshpdkshところでこれも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

どれ匿名関数通話のみがサポートさzshれます。

答え4

これまで、他の人が正しく答えてきましたが、ここに簡単な要約があります。

2番目のバージョンは移植可能で、多くの標準(特にPOSIX)シェルで使用できます。

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

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

関連情報