2011-01-07 13 views
9

私が知る限り、bash関数でローカル変数を作成するには2つの方法があります:サブシェルを作成するか、すべての変数をローカルとして宣言します。bashのローカル変数:ローカルとサブシェル

例えば:

# using local 
function foo 
{ 
    local count 
    for count in $(seq 10) 
    do 
    echo $count 
    done 
} 

または

# using subshell 
function foo 
{ 
    (
    for count in $(seq 10) 
    do 
     echo $count 
    done 
) 
} 

Obvisouslyあなたはすべてのローカル変数(ないに言及し(宣言を気にする必要はありませんので、サブシェルを使用したバージョンは、書くことが簡単です環境変数)は、getoptsのようなツールで作成/エクスポートされた変数です。しかし、私は、サブシールの作成にはオーバーヘッドがあると想像することができます。

だから、よりよいアプローチは何ですか?賛否両論は何ですか?

+0

を終了します、だけでなく1000回のテストの上に 'time'のコマンドを実行し、見つけますオーバーヘッドから、私はそれが存在しない小さいですと思う。 – Anders

答えて

9

サブシェルの作成にはfork()が含まれているため、ローカル変数と比較してオーバーヘッドがあります。サブシェルは安いですが—あなたは1つが必要なときにその費用について心配しないでください—彼らは無料ではありません。

スクリプトが頻繁に使用され、パフォーマンスが重要な場合(つまり、何百ものユーザーが一度に何度も同じ時間に複数のユーザーを実行することになります)、サブシェル。 OTOH、あなたが月に一度それを実行し、スクリプト全体が10秒未満で実行される場合、あなたはおそらくそうではありません。

しかし、明確にすることと、変数を宣言する方がはるかに優れています—誰かが来て「このサブシェルは必要ありません」と実際にはそうではありません;私はあなたの関数からサブシェルを削除したいと思います)。

Perlスクリプトの進化を見てください。彼らは、必要に応じて存在する変数を自由に使用することから始めました。彼らは徐々により厳密になり、通常のスタイルはすべての変数を事前に宣言しています。ある程度、シェルは同じようなパスをたどっていますが、Perlほど厳密ではありません。— Awkも興味深いケーススタディです。その関数は、関数への引数でない限りグローバル変数を使用します。これは、3つのアクティブな引数(例えば)と5つの非アクティブな引数を使用して関数を作成し、効果的にローカル変数を定義します。それはちょっと偏心していますが、それはうまくいきます。

0

すべての関数が常にすべての変数をローカルとして宣言していることを確認することは非常に困難です。

は、私は、これは非常にエラーが発生しやすいと考え、常にサブシェル-機能を使用することを好む:

f() (
echo "we are a subshell" 
) 

ローカル変数を宣言する必要はありません - だけでなく、グローバル変数を変更する方法はありません。私の意見ではどちらが良いです!

もう1つの結果は、常にそのような関数の戻り値/終了コードをチェックし、それに応じて行動する必要があることです。 これは、サブシェル関数内からスクリプトを終了することができないためです。

f() (
    echo "Trying to exit" 
    exit 1 
) 

f 
echo "Did not exit" 

これでスクリプトは終了しません。 あなたはこのようにそれを実行する必要があります「しかし、私はサブシェルを作成するオーバーヘッドを持っていることを想像できる」

f() (
    echo "Trying to exit" 
    exit 1 
) 

f || exit $? 
echo "Did not exit" 

これは