ソーススクリプトで名前空間の競合/汚染を防ぐ方法は?

ソーススクリプトで名前空間の競合/汚染を防ぐ方法は?

foo.sh最終的にコマンドを実行するスクリプトbar(一部のパラメータを使用)を実装したいと思います。このコマンドはbar現在のシェル環境を変更します。つまり、1foo.shから始める必要があります。 (しかし、実装は完全に私のコントロールの範囲外です。)bar

のほとんどのコードの目的はfoo.shに渡されるパラメータを計算することですbar

合理的な読みやすさ/メンテナンス性を維持するためにfoo.sh多くの補助変数を定義する必要があることがわかりました。残念ながらこれ

  1. 名前空間の競合(たとえば、既存のパラメータの削除)
  2. 名前空間の汚染(例:冗長パラメータで環境を複雑にする)

これらの問題を回避または最小限に抑えるための1つの可能な方法は、呼び出し範囲に含まれる適切なコード文字列をfoo.shエコーする関数(すべての変数が宣言されている状態)にほとんどのコードを配置することです。localeval

{
  __messy_calculation () {

      local x y z ...
      local bar_arg_1 bar_arg_2 ...
      ...
      echo "bar $bar_arg_1 bar_arg_2 ..."

  }

  eval "$( __messy_calculation )"

} always {

  unfunction __messy_calculation

}

これは名前空間の汚染問題を解決し、名前空間の競合の問題を関数名の問題に減らします。 (私はevalを使うのがあまり好きではありません。)

私の考えでは、この状況は、これを解決するための標準的な方法がすでに存在するのに十分一般的であると思います。その場合はお知らせください。


1bar私の推論に欠陥がある場合、すべてのコード(呼び出しを含む)を関数に入れると、コマンドラインでこの関数を実行すると現在の環境が影響を受けず、関数が役に立たなくなることを追加します。 。代わりに、呼び出しが行われた行を取得すると、bar現在の環境が期待どおりに変更されます。

答え1

変数の場合は、上記の説明で説明したように、匿名関数を使用できます。これは、必要な数の変数を定義できることを意味します。接頭辞付きの発信者から非表示にすることlocal、通常定義する発信者と通信しようとしているもの:

function {
  local my_var=foo
  your_var=bar
  : ...
}

ただし、関数の場合は宣言できないため、機能しませんlocal。私にはこの問題があります。zshrcunfunctionそして、私の「ローカル」関数のすべての名前に短い文字列プレフィックスを追加し(名前空間を持つCと同じように)、最後にワイルドカードを追加することにしました。

function foo-do-something () {
  : ...
}
function foo-do-some-more-stuff () {
  : ...
}
function foo-main () {
  local my_var=oof
  you_var=rab
  foo-do-something for bar
  foo-do-some-more-stuff with baz
}
foo-main
unfunction -m 'foo-*'

私の考えではこれが最善の解決策ではありませんが(私はローカル機能を好む)私には効果があります。

答え2

解決策は、サブシェル、ネストされた関数、およびunset基本機能を使用することです。

my_app_main()
(
  unset -f my_app_main

  a()
  (
    x=1
    echo "a.x is $x"
  )

  b()
  (
    x=2
    echo "b.x is $x"
  )

  c()
  (
    echo "c.x is $x (empty)"
  )

  a
  b
  c
)

my_app_main "$@"

echo "$x (empty - x is gone)"

# all gone
type my_app_main a b c

関連情報