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


96

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

#!/bin/bash

function foo() {
  echo "foo"
}

bar() {
  echo "bar"
}

foo

bar

関数の呼び出しfoobar成功の両方で、違いは見当たりません。だから、読みやすさを改善するだけなのか、それとも私が見逃しているものがあるのか​​疑問に思っています...

BTW dash(debian / ubuntuに/bin/shシンボリックリンクさdashれています)などの他のシェルでは、functionキーワードを使用すると失敗します。


8
また、括弧の有無にかかわらずfunction baz { echo "baz"; }。GreyCatのwikiのBashismを参照してください。
マナトワーク

回答:


42

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


32
これは大きな違い、移植性です...(古い)本番システムでは機能しないだけでなく、Linuxでのみ機能するオプションを備えた多くの回答があります。少なくとも、これは最もポータブルな方法ではないことを警告してください...それはまったく危険です(tar cf - /some/thing | ssh user@desthost "cd destinationdir && tar xf - " desthost上のtarのバージョンが「/」を取り除くことができるかどうかを最初にダブルチェックするように警告せずに誰かに尋ねることができます)場合によっては災害...)。例の場合:ユースAの場合function tar { #a safe tar with safety checks ... }sh、それを無視し、...
オリヴィエ・デュラック

1
@OlivierDulacはshfunctionキーワードを認識することを前提とするスクリプト、および一般的に、シェルが好んkshbash提供する一般的だが非標準の機能を前提とするスクリプトは、新しいリリースのシステムで動作していても、しばしば動作しないことを追加します同じOS。bashまだsh多くのGNU / Linuxシステムで提供されていますが、一部の人気ディストリビューションは(Debian Almquist SHell)へのshシンボリックリンクとして切り替えてdashパフォーマンスを改善しています。これにはDebianUbuntuが含まれます
エリアケイガン

2
どれだけ正確に「ポータブル」であるかを詳しく説明しないと、答えは役に立ちません。
ivan_pozdeev

業界がすべての環境の99.9%以上でbashまたは同等のシェルを使用している今日、移植性は議論の余地がありません。それは読みやすさに要約されており、2つの側面があります。一部の人々は「機能」がそれを明らかにすると言う人もいます。最後に、グループまたは会社内のいずれかを選択し、それに固執します。
ヒューバート・グジェスコウィアク

93

functionキーワードがで導入されたのksh。従来のBourneシェルにfoo ()構文のみがあり、POSIXfoo ()構文のみを標準化します。

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

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

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


8
Bourneシェルが構文を導入するに、Kornシェル関数サポートが追加され、foo() command後で互換性のためにBourne構文がKornシェル追加されたことに注意してください。
ステファンシャゼル

2
キーワードの後にfunction { ... }; f;省略するのは正しいですか?ffunction
ルスラン

32
foo() any-command

は、Bourneに似たシェルでサポートされているBourne構文ですがbash、のyash最新バージョンposh(複合コマンドのみをサポート)です。(ただし、BourneシェルおよびAT&Tの実装は、複合コマンドでない限りkshサポートしません)。foo() 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ではなく、によってサポートされているbashyashzshKornシェルとの互換性のために、それらのシェル(及びもののpdkshKornシェルのベースの変異体は)それを標準構文から任意の異なる扱いません。

function foo () { ...; }

no shell の構文であり、使用するべきではありません。それだけで事故によってサポートされるたまたまbashyashzshおよびpdkshKornシェルのベースの変種。ちなみに、それはawk関数の構文でもあります。

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

function foo() other-compound-command

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

一方:

function foo() simple command

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


1
functionキーワードと括弧の両方を含む構文は、Bashに文書化されています。Bash 4.2以降のマニュアルでは、関数は構文name () compound-command [ redirections ]またはで宣言されていますfunction name [()] compound-command [ redirections ]。Bash 4.1.11から少なくとも3.0-betaまで[ function ] name () compound-command [redirection]は、functionキーワードを含むが括弧を含まない構文を誤ってカバーせず、functionキーワードと括弧の両方を含む構文をカバーする単一行でした。
ニセタマ

@niseのポイントは、Kornシェルとの互換性に加えて(常に持っている)bash認識function foo {foo() {て、Kornシェル用に記述されたスクリプトを解釈できるようにすることです。サポートfunction foo () {も行いますが、それを使用する正当な理由はありません。
ステファンシャゼラス

2
@StéphaneChazelasまあ、使用する正当な理由があると思いますfunction f() {。つまり、読みやすさの観点からは、英語を知っている人とCを知っている人が、これらのセットの1つだけに対して関数として認識されるでしょう。
-DepressedDaniel

2
受け入れられた答えであるべきです。本当に重要You should never combine the keyword function with the parentheses () when defining a function.
週目_

2019年へようこそ。Linux/ unix自動化スクリプトの業界標準は1つだけです。ほとんどすべての場所(エキゾチックな環境は別として)にインストールされる1つのインタープリター:bash。すべてのbash機能を使用してコードを記述し、シバンを使用すれば大丈夫です。互換性の引数は無効です。
ヒューバート・グジェスコヴィアック

22

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

manページから:

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

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

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

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


3

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

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

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

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


実際、最初のバージョンは、一部のシェルに受け入れられる構文として制限する以外は意味がありません。キーワード() functionキーワードを含める、シェルはfoo(){ ...; }とにかく実行したかのように動作します。ただし、もちろん、構文が無効なシェルは例外です。そのため、必要なfunction foo { ...; }場合はそうする必要がありfoo(){ ...; }ます。
mikeserv
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.