bash:グローバル変数コンテキストの保存と復元の実験

bash:グローバル変数コンテキストの保存と復元の実験

1行にいくつかのコンテキストを保存するためにいくつかの実験を行った。

私が望むように正確に動作します。したがって、この投稿の目的は次のとおりです。 1. コミュニティと共有します。 2.醜くて不思議なので、改善するか、まったく異なる解決策を見つけてください。

状況は次のとおりです。グローバル変数があり、関数をローカルに変更して最後に復元できるようにしたいです。

x()
{
    typeset loc=$glob
    glob=<val>
    (...)
    glob=$loc
}

これは私にとってとても冗談で、タイプミスが必要です。

だから私はこれを試しました(利用可能なコード):

#!/bin/bash

glob=1
indent=0

# appliance
trace()
{
   printf "%$((${indent}*3))s %s\n" "" "$1"
}

# the context stuff (creation and destruction)
# in variable, because with a function, I'd need to create a $(sub shell) and it wouldn't work
new_glob='trap restore_context RETURN;typeset loc=$glob;glob'

restore_context()
{
   res=$?
   glob=$loc
   trap - RETURN
}

# common test stuff, to isolate the traces
test_call()
{
   typeset res
   trace "in ${FUNCNAME[1]}, before $1,glob=$glob"
   (( indent++ ))
   eval $1
   res=$?
   (( indent-- ))

   trace "in ${FUNCNAME[1]}, res of $1=$res"
   trace "in ${FUNCNAME[1]}, after $1,glob=$glob"

   return $res
}

# Russian dolls function
f()
{
   eval "$new_glob=6"
   test_call g
   return 16
}

g()
{
   eval "$new_glob=7"
   test_call h
   return 17
}

h()
{
   eval "$new_glob=8"
   trace "in h, glob=$glob"
   i
   return 18
}

i()
{
   trace "in i, glob=$glob"
}

# main
test_call f

このスクリプトはfを呼び出し、fはgを呼び出し、gはhを呼び出します。各関数はグローバル変数を変更して復元します。

出力:

# ./test_rtrap
 in main, before f,glob=1
    in f, before g,glob=6
       in g, before h,glob=7
          in h, glob=8
          in i, glob=8
       in g, res of h=18
       in g, after h,glob=7
    in f, res of g=17
    in f, after g,glob=6
 in main, res of f=16
 in main, after f,glob=1

ここで重要なのは、私()ローカル変数を使用するのと同じように、1ではなく8を印刷します。

この結果を得るために、RETURN にトラップ機能を使用しました。

さて、上記の関数xは次のようになります。

x()
{
   eval "$new_glob=6"
   (...)
}

残念ながら、コードの一部を含む試用版と変数を使用する必要があります。不自然で、かなり神秘的です。しかし、そこで関数を使用するにはサブシェルが必要で、関連する変数コンテキストの問題があるため必要です。

したがって、完璧ではありませんが、きれいではなく冗談ではありませんが、うまくいきます。

醜い評価「$new_glob=6」より良い方法はありますか?

ベストアンサー1

まあ!少なくとも示された例ではそうである。

new_glob変数eval "$new_glob=6"に置き換えて削除します。local glob=6

つまり、書くより

x()
{
   typeset loc=$glob
   glob=<val>
   (...)
   glob=$loc
}

書く

x()
{
   typeset glob
   glob=<val>
}

オプションでまたはtypesetに置き換えます。localdeclare

バッシュダイナミックレンジ言語。現在の実装戦略はリンクされた記事で説明されています。

より単純な実装は、単純なグローバル変数を使用して動的変数を表すことです。ローカルバインディングは、プログラムに見えないスタックの匿名位置に元の値を格納することによって実行されます。バインド範囲が終了すると、元の値がこの場所から復元されます。実際、ダイナミックレンジの指定はこのように始まった。 Lispの最初の実装では、ローカル変数を実装するためにこの確かな戦略を使用し、GNU Emacs Lispなど、まだ使用されているいくつかの方言ではこれらの慣行が維持されました。

提供されたbashコードをほとんど説明します。

おすすめ記事