什么是
declare name
不提供任何选项怎么办?它声明一个字符串变量的名称吗?
什么是
declare -g
不提供变量名怎么办?它会显示所有具有全局属性的变量的值吗?
declare
我在Bash 手册的描述中没有找到答案。
谢谢。
答案1
shell 中的变量处理和作用域尤其bash
可能非常晦涩且不直观(有时还有错误)。
ksh
具有typeset
类似的功能。ksh
,zsh
,yash
有typeset
。bash
hastypeset
作为 的别名declare
与 兼容ksh
,zsh
hasdeclare
作为 的 别名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
// 。它仅适用于尚未声明的变量yash
zsh
bash
当地的由调用者:
$ 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 var
。export
如果变量已经存在,它会添加属性而不声明新变量。readonly
vs也是一样typeset -r
。
另请注意,unset
如果bash
变量已在当前范围内声明,则仅取消设置该变量(尽管在全局范围内除外,但仍保留其声明;它删除属性和值,并且该变量不再是数组或散列;另请注意,在 namerefs 上,它取消设置引用的变量)。否则,它只是从上面提到的堆栈中弹出一个变量层。对于bash
5.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
declare name
声明名为 的变量name
,不带任何属性;你可以使用${name:not set}
例如看到它的效果。声明的变量不是数组,并且没有设置整数属性,因此您可以将其视为字符串变量,但在算术表达式中其计算结果为 0。来自联机帮助页:
该
-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
基于您之前的命令;返回的变量列表没有其他区别。