%7B%7D%E3%80%8D%E3%81%A8%E3%80%8Cfoo()%7B%7D%E3%80%8D%E3%81%AE%E9%81%95%E3%81%84.png)
bash
関数を定義するためにキーワードを使用または省略できますfunction
。違いはありますか?
#!/bin/bash
function foo() {
echo "foo"
}
bar() {
echo "bar"
}
foo
bar
関数への呼び出しはすべてfoo
成功し、bar
違いは見られません。それで、これが単に可読性のためであるのか、それとも何か抜けたのかどうか疑問に思います。
ただし、他のシェル(dash
debian / 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
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のもう1つの違いは、function
キーワードを使用して定義された関数に独自のトラップコンテキストがあることです。関数が実行されると、関数の外部で定義されたトラップは無視され、関数内の致命的なエラーはスクリプト全体ではなく関数でのみ終了します。また、$0
で定義された関数の関数名ですが、function
で定義された関数のスクリプト名です()
。
Pdksh は ATT ksh をエミュレートしません。 pdkshではtypeset
機能に関係なくローカルスコープ変数が生成され、ローカルトラップはありません(使用によってはわずかなfunction
違いがありますが、詳細についてはマニュアルページを参照)。
Bashとzshはfunction
ksh互換キーワードを導入します。ただし、これらのシェルでは bash および zsh 拡張と同様に厳密に同じですfunction foo { … }
(上記のように定義を解析する際の潜在的なエイリアス拡張を除く)。キーワードは常にローカル変数を宣言します(もちろん除外)、トラップはローカルではありません(オプションを設定してzshからローカルトラップを取得できます)。foo () { … }
function foo () { … }
typeset
-g
local_traps
答え2
私が知っている限り、2番目のバージョンは移植性が良いということ以外に違いはありません。
答え3
foo() any-command
Bourneに似たシェルでサポートされているBourne構文ですがbash
、yash
と最新バージョンposh
(複合コマンドのみサポートksh
)foo() any-command > redirections
any-command
foo() any-compound-command
(複合コマンドの例:{ cmd; }
、、、for i do echo "$i"; done
...(cmd)
最も一般的に使用されます{ ...; }
)
Bourneに似たシェルでサポートされているPOSIX構文で、一般的に使用したい構文です。
function foo { ...; }
Bourne 構文の前にある Korn シェル構文です。 Korn シェルの AT&T 実装用に特別に作成し、そこで受け取る特定の処理が必要な場合にのみ、このオプションを使用してください。この構文はPOSIXではありませんが、Kornシェルでサポートされていますbash
。yash
ただしzsh
、これらのシェル(およびpdksh
Kornシェルの - ベースのバリエーション)はこれを標準構文とは異なって扱いません。
function foo () { ...; }
構文は次のとおりです。いいえシェルと使用しないでください。これはbash
、およびKornシェルyash
の基本的なバリエーションでのみ偶然サポートされます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
れます。
答え4
これまで、他の人が正しく答えてきましたが、ここに簡単な要約があります。
2番目のバージョンは移植可能で、多くの標準(特にPOSIX)シェルで使用できます。
最初のバージョンはbashでのみ機能しますが、関数名の後の括弧を省略できます。
それ以外の場合、bashはそれを解釈した後に同じエンティティを表します。