1.ksh93

1.ksh93

https://unix.stackexchange.com/a/381782/674

例如:

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

要使变量成为整数,可以使用mksh// 。它适用于yashzshbash仅适用于尚未声明的变量当地的由调用者:

$ 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 var也不是typeset -gx varexport如果变量已经存在,它会添加属性而不声明新变量。与readonlyvs相同typeset -r

对于bash,

  • f第一个示例中,integer a声明aa内部声明不同的内容f或使a内部声明f具有全局作用域有何作用?为什么会输出1+1

  • f第二个示例中,是否integer a 声明a了全局范围?为什么会输出2

对于 zsh,同样的问题,除了为什么第一个示例输出2而不是1+1bash?

我说得对吗

  • bash 和 zsh 都使用动态作用域,至少在示例中是这样?
  • -gbash 和 zsh 中的选项typeset意味着声明一个具有全局作用域的不存在的变量,或者更改一个现有的变量以具有全局作用域?

谢谢。

答案1

  • 在编程语言中静态范围,例如大多数其他编程语言(如 C),

    每个函数都有一个全局作用域和一个局部作用域。函数中出现的变量要么是函数私有的,要么是全局的。

    一个函数只能访问其中一个它是局部变量或全局变量。除了通过引用传递之外,它无法访问另一个函数(甚至是其调用者)的变量。

  • 在编程语言中动态范围界定,

    函数可以看到其调用者的变量,并且该函数的调用树中的每个函数都有一个作用域。范围界定就像俄罗斯套娃,变量堆叠在另一个之上。

    在该范围堆栈中,全球的作用域的唯一特殊之处在于它是最底部的作用域,但如果函数已被调用树中的任何函数将其屏蔽为局部变量,则函数不一定会看到该作用域中的变量。所以不存在一个全局作用域和一个局部作用域。


了解这里的历史很有帮助。

1.ksh93

  1. ksh93一个函数,至少一个使用 ksh 语法声明的函数 ( 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. ksh93使用 Bourne 语法声明的函数 (f() {...} )根本不进行范围界定。在这方面,该函数的代码看起来就像嵌入式在函数的调用者中,因此其中出现的任何变量都将具有与调用者相同的作用域,因此对于在其调用树中使用 ksh 语法声明的最顶层函数来说,无论是全局变量还是局部变量。typeset将在最顶层函数中声明变量(如果其调用树中没有 ksh 语法函数,则在全局范围内声明变量)。

    例如,由于在 ksh-syntax 函数中,所有变量都是私有的或全局的,要实现我们的integeras in bash,我们需要这样做:

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

    那是使用 Bourne 函数语法这根本不做范围界定。

    或者使用 ksh 语法:

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

    但要被调用为:

    . integer var
    

    (也就是说,通过使用.,整数代码在调用者的上下文中解释,就像您在脚本上调用.( ) 时一样。source

    或者使用ksh 语法:

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

    在哪里该变量作为引用传递就像-n您在 C 或大多数其他编程语言中所做的那样。

2. 所有其他类似 Bourne 的 shell

所有其他类似 Bourne 的 shell(包括 ksh88、ksh93 是完全重写和静态作用域的更改是(至少被认为是)功能包含在 POSIX 标准中的先决条件) 实施动态范围界定

  1. 在函数中用typesetwithout声明的变量具有该函数的局部作用域。-g

    例如,typeset -i var将声明变量 local(在当前函数范围内)并设置整数属性。

    例如,在顶部的代码中,它们都会输出f_a.也就是说,g确实看到了 的局部变量f

    再举个例子,如果f调用g则调用h.如果h不声明var变量当地的在其作用域中,它将看到 g's 变量,或者可能看到f's (如果g尚未声明为var本地变量),或者可能看到来自最底部作用域的变量。

  2. 在所有bash, zsh, yash, mksh,可以使用以下命令更改函数中变量的类型或值,而无需使其成为该函数的本地变量typeset -g。就像integer您引用的示例中的该函数一样 。但根据外壳的不同,它的做法也有所不同。

    • mkshyashzshtypeset -g 不影响最底部的变量(全球的) 范围,但是 在当前定义的范围内

      例如, whiletypeset -i var将声明变量 local(在当前函数作用域中)并设置整数属性,typeset -gi var只执行后一部分(不影响 的范围var)。

      例如,当函数调用integer上面的函数将整数属性添加到变量时,如下所示:

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

      它确实想integer改变的属性它是 myvar变量,而不是它不知道并且可能无法访问的全局范围内的变量。

    • bash,typeset -g影响变量的实例在全局(最底层)范围内。虽然这就是 的含义g,但它在具有动态作用域(如 bash.

      例如,在你问题的第一个例子中,1+1 输出表明整数属性尚未添加到变量中。它已被添加到A全局范围内的变量 ,但不是函数有权访问的a变量。f

相关内容