BASHのローカル変数:ローカルとサブシェル
質問
私が知る限り、バッシュ関数にローカル変数を作成する方法は2つあります。サブシェルを作成するか、すべての変数をローカルとして宣言します。
例えば:
# 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
)
}
サブシェルを使用するバージョンは、すべての変数をローカル(言うまでもなく(環境)変数を宣言することを気にする必要がないため、書くのが簡単です。 getopts)。しかし、サブシェルを作成するには頭上があると想像できました。
では、より良いアプローチは何ですか?長所/短所は何ですか?
解決
サブシェルを作成するには、aが含まれます fork()
, 、そのため、ローカル変数と比較して間違いなく頭上にあります。サブシェルは安いですが、必要なときにコストを心配する必要はありませんが、無料ではありません。
スクリプトが頻繁に使用され、パフォーマンスが実際に重要である場合(そのため、何百人ものユーザーが1日に何度もそれを実行している場合があります)、サブシェルのパフォーマンスコストについて心配するかもしれません。 OTOH、月に一度実行し、スクリプト全体が10秒以内に実行されると、おそらくそうしないでしょう。
ただし、明確さの観点からは、変数を明示して宣言する方がはるかに優れています。誰かがやって来て、「このサブシェルは明らかに必要ない」と言っているため、スクリプトが壊れるリスクを軽減します(そして、それは本当にそうではありません」 T;私はあなたの関数からサブシェルを削除したいと思います)。
Perlスクリプトの進化を見てください。彼らは、変数がオンデマンドで存在するようになった自由に始まりました。彼らは徐々により厳格になり、通常のスタイルはすべての変数を事前にすることです。ある程度、シェルは同様の道をたどっていますが、Perlほど厳密ではありません。 AWKは興味深いケーススタディでもあります。その関数は、関数の引数でない限り、グローバル変数を使用します。これは、3つのアクティブな引数(たとえば)と局所変数を効果的に定義する5つの非アクティブな引数で書かれている関数につながります。 「機能する」にもかかわらず、わずかに偏心しています。
他のヒント
これで、すべての関数が常にすべての変数をローカルとして宣言することを確認することは非常に困難です。
これは非常にエラーが発生しやすいと思いますが、常にサブシェルファンクションを使用することを好むと思います。
f() (
echo "we are a subshell"
)
ローカル変数を宣言する必要はありませんが、グローバル変数を変更する方法もありません。私の意見ではそれは良いことです!
追加の結果の1つは、そのような関数の返品 / exitコードを常に確認し、それに応じて行動する必要があることです!これは、サブシェル関数内からスクリプトを終了できないためです!
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"
これは終了します