1.ksh93

1.ksh93

~からhttps://unix.stackexchange.com/a/381782/674

たとえば、

integer() { typeset -gi "$1"; }

変数を整数にするには//を使用できますmkshyashzshbashまだ宣言されていない変数に対してのみ機能します。地元の発信者:

$ bash -c 'f() { declare a; integer a; a=1+1; echo "$a"; }; integer() { typeset -gi "$1"; }; f'
1+1
$ bash -c 'f() { integer a; a=1+1; echo "$a"; }; integer() { typeset -gi "$1"; }; f'
2

でも、でもありexport varませtypeset -x vartypeset -gx varexport変数がすでに存在する場合は、新しい変数を宣言せずに属性を追加します。readonly対。とtypeset -r同じ

バッシュの場合、

  • f最初の例では、内部宣言とは異なるものをinteger a宣言したり、a内部宣言にグローバルスコープを持たせたりするにはどうすればよいですか。なぜ出力されますか?afaf1+1

  • f2番目の例では、グローバルスコープがinteger a 宣言されていますかa?なぜ出力されますか2

zshについても同じ質問です。しかし、最初の例がbashの2代わりに出力されるのはなぜですか1+1

私は正しいですか?

  • 少なくとも例では、bashとzshの両方が動的スコープを使用していますか?
  • -gbashとzshのオプションは、typeset存在しない変数をグローバルスコープとして宣言するか、既存の変数をグローバルスコープに変更することを意味しますか?

ありがとうございます。

ベストアンサー1

  • プログラミング言語で静的範囲、たとえば、他のほとんどのプログラミング言語(例:C)、

    すべての関数にはグローバルスコープとローカルスコープがあります。関数に表示される変数は、関数専用またはグローバル変数です。

    関数はそのうちの1つだけにアクセスできます。それローカルまたはグローバル変数。参照に渡す以外に、他の関数(またはその呼び出し元)の変数にアクセスすることはできません。

  • プログラミング言語で動的範囲の指定

    関数は呼び出し元の変数を見ることができ、関数呼び出しツリーの各関数には範囲があります。範囲指定は、変数が重なっているロシアのマトリョーシカ人形と同じです。

    この範囲スタックではグローバル範囲の唯一の特別な点は、範囲が最も下にあることです。ただし、関数が呼び出しツリーの関数によってローカル変数としてマスクされている場合、関数はその範囲内の変数を必ずしも見ることはできません。したがって、グローバルスコープとローカルスコープはありません。


ここの歴史を知ることが役に立ちます。

1.ksh93

  1. 存在するksh93ksh 構文を使用して宣言された関数( function f {...})、次のように静的範囲

    typeset関数内で宣言された変数は、その関数に対してローカルです。

    a=global_a
    function f {
      typeset a=f_a
      g
    }
    
    function g {
      echo "$a"
    }
    
    f
    

    出力されますglobal_a

    typeset -i var機能でタイプが変更されました。地元の var変数が関数スコープでまだインスタンス化されていない場合、変数はインスタンス化されます。

  2. 存在するksh93Bourne 構文を使用して宣言された関数( f() {...})範囲指定はまったくありません。これに関して、関数のコードは次のようになります。埋め込み関数呼び出し元では、その中に現れるすべての変数は呼び出し元と同じ範囲を持つため、呼び出しツリーでksh構文を使用してグローバルまたはローカルに宣言された最上位関数の場合。typeset変数は最上位関数で宣言されます(または呼び出しツリーにksh構文関数がない場合はグローバルに)。

    たとえば、ksh-syntax関数では、すべての変数はプライベートまたはグローバル変数であるため、integerasを実装するにはbash次のようにする必要があります。

    integer() { typeset -i "$1"; }
    

    それはBourne 関数構文の使用これは範囲指定をまったく行いません。

    またはksh構文の使用:

    function integer { typeset -i "$1"; }
    

    ただし、次のように呼び出されます。

    . integer var
    

    (つまり、使用..、整数コードは、スクリプトで()を呼び出すときと同様に、呼び出し元のコンテキストで解釈されます。source

    または使用ksh構文:

    function integer { typeset -ni "$1"; }
    

    どこ変数が参照として渡されます。-nCや他のほとんどのプログラミング言語と同じです。

2. 他のすべての Bourne 同様のシェル

他のすべてのBourne様シェル(ksh88を含むksh93は完全に書き直されました静的スコープの変更は、POSIX標準に含まれる機能の前提条件です(少なくとも考慮されます)。) 実装動的範囲の指定

  1. 関数内でtypesetなく宣言された変数は、その関数のローカル範囲を持ちます。-g

    たとえば、typeset -i var変数をローカル(現在の関数の範囲内)で宣言して設定します。整数属性。

    たとえば、上部のコードではすべて出力ですf_a。つまり、gローカル変数が実際に表示されますf

    別の例として、変数がf宣言されていない場合にg呼び出されますhhvar地元のgその範囲内ではの変数を見ることができ、ローカルで宣言されていないf場合の変数を見ることもでき、最下位の範囲の変数を見ることもできます。gvar

  2. 全体的に bash、、、、、、​zshyashmksh次のコマンドを使用すると、関数にローカルにすることなく、関数内の変数の型または値を変更できます。typeset -ginteger引用した例のこの機能と同じです。しかし、シェルによって異なります。

    • 存在するmksh、、、yashzshtypeset -g 下の変数には影響しません(グローバル) 範囲ですが 現在定義されている範囲内で

      たとえば、whileはtypeset -i varローカル変数(現在の関数範囲内)を宣言して設定します。整数プロパティ、typeset -gi var後半のみが実行されます(範囲には影響しませんvar)。

      たとえば、関数が上記のinteger関数を呼び出して、次のように整数プロパティを変数に追加する場合:

      f() {
       local myvar
       integer myvar
       ...
      }
      

      integer変更したい属性それ myvar認識されず、アクセスできないグローバル範囲の変数ではない変数。

    • 存在するbashtypeset -g変数に影響を与えるインスタンスグローバル(最下位レベル)範囲。それが意味するのはですがg、 のような動的範囲ではうまく動作しません bash

      たとえば、質問の最初の例では、出力は1+1 整数属性が変数に追加されなかったことを示します。に追加されましたグローバルスコープの変数ですが、a関数がアクセスできる変数ではありません。f

おすすめ記事