`declare name` 和 `declare -g` 有什么作用?

`declare name` 和 `declare -g` 有什么作用?
  1. 什么是

    declare name
    

    不提供任何选项怎么办?它声明一个字符串变量的名称吗?

  2. 什么是

    declare -g
    

    不提供变量名怎么办?它会显示所有具有全局属性的变量的值吗?

declare我在Bash 手册的描述中没有找到答案。

谢谢。

答案1

shell 中的变量处理和作用域尤其bash可能非常晦涩且不直观(有时还有错误)。

ksh具有typeset类似的功能。kshzshyashtypesetbashhastypeset作为 的别名declare与 兼容kshzshhasdeclare作为 的 别名typeset与 兼容bash。大多数 shell 都有export,readonly并且local实现了部分功能typeset

bash作者选择declare的原因之一typeset可能是因为typeset它不仅设置了类型,还设置了类型。宣称变量:将其引入给定范围,可能带有类型、属性和/或值。

在 中bash,变量可以是:

  • 未知(例如从未设置或声明它们时)
  • 声明(之后declare
  • 设置(当给定值时,可能为空)。

它们可以有不同的类型:

  • 标量
  • 大批
  • 关联数组

并且有几个属性:

  • 整数
  • 出口
  • 只读
  • 全部小写/全部大写
  • 命名参考

(尽管类型和属性之间的区别可能相当模糊)。

并非所有类型和属性的组合都受支持或有效。

现在,declare在当前作用域中声明变量。bash,即使它实现了动态作用域,也会特别对待最外层的作用域。它称之为全球的范围。

declare当它被调用时,行为非常不同全球的范围以及何时在函数中(我不是在谈论由子 shell 引入的或与环境关联的那种单独的范围)。

当您declare var在函数内部执行操作并假设未在同一作用域中声明相同的变量时,它宣称A新的最初未设置的变量,它隐藏了var父作用域(函数的调用者)中可能存在的潜在变量。

这是通过某种堆栈实现的动态作用域。当函数退出时,变量的状态、类型、属性和值将恢复到调用函数时的状态(从堆栈中弹出)。

然而,在任何函数之外(在全局范围内),declare确实声明了一个变量,但如果之前设置了该变量,则不会将其初始化为未设置(与declare在同一函数范围内第二次使用时相同)。如果指定了类型,则可以转换变量的值,但并非允许所有转换路径(仅标量到数组/散列),并且可以添加或删除属性。

在 中bash,函数内declare -g作用于最外层(“全局”)作用域中堆栈底部的变量。

declare -g受到ksh93启发typeset -g。但ksh93实现静态作用域,其中全局作用域不同并且与每个函数作用域分开。对动态作用域做同样的事情没有什么意义。在所有其他具有typeset -g( mksh, zsh, yash)的 shell 中,typeset -g用于更改变量的某些属性,而不实例化新的本地变量。

在 中bash,人们通常将它用于相同的目的,但由于它影响的是最外层作用域的变量而不是当前变量,因此它并不总是有效。

例如:

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

另请注意,unset如果bash变量已在当前范围内声明,则仅取消设置该变量(尽管在全局范围内除外,但仍保留其声明;它删除属性和值,并且该变量不再是数组或散列;另请注意,在 namerefs 上,它取消设置引用的变量)。否则,它只是从上面提到的堆栈中弹出一个变量层。对于bash5.0 或更高版本,可以通过设置localvar_unset选项来修复。

总结一下:

 declare var

当在函数中调用时,如果var之前没有在同一函数中声明过,则声明一个类型的变量标量没有属性并且最初未设置。

如果在任何函数外部调用或者已经var在同一函数中声明,则它无效,因为我们没有指定任何新类型或属性。

declare -g var

无论在哪里调用它都会var在最外层(“全局”)范围内声明 a :宣布,类型标量,没有属性,如果之前在该范围内未知,则没有值(从所有意图和目的来看,它与未知变量相同,除了它会显示在 的输出中typeset -p),否则不执行任何操作。

在任何情况下,您可能无法在运行该命令的上下文中访问该变量:

f() { local a; g; }; g() { typeset -g a=123; echo "$a"; }; f

什么也不输出。

答案2

  1. declare name声明名为 的变量name,不带任何属性;你可以使用${name:not set}例如看到它的效果。声明的变量不是数组,并且没有设置整数属性,因此您可以将其视为字符串变量,但在算术表达式中其计算结果为 0。

  2. 来自联机帮助页:

    -g选项强制在全局范围内创建或修改变量,即使declare在 shell 函数中执行也是如此。在所有其他情况下都会忽略它。

    所以declare -g不带参数和 是一样的declare

答案3

declare name

From https://www.gnu.org/software/bash/manual/bashref.html#Bash-Builtins

声明变量并赋予它们属性。

您尚未提供任何选项,因此未分配任何属性,并且name已创建变量。未提供任何值,因此未分配任何值。

declare -g

-g 选项强制在全局范围内创建或修改变量,即使在 shell 函数中执行 statements 时也是如此。在所有其他情况下都会忽略它。

由于您没有提供 a name,因此不会创建任何变量,因此它会被忽略。你自己看:

declare -g > foo
declare > bar
diff foo bar

唯一的区别可能是 Bash 变量的值$_,并且可能PIPESTATUS基于您之前的命令;返回的变量列表没有其他区别。

相关内容