简单的问题。 bash shell 是否支持在编写 shell 脚本时使用指针?
${var[@]}
在迭代数组时,我熟悉扩展符号$var
,但不清楚这是利用指针迭代数组索引。 bash 是否像其他语言一样提供对内存地址的访问?
如果 bash 不支持使用指针,其他 shell 会做什么?
答案1
一个指针(指向某个位置记忆) 在任何比 C 更高级别的东西中都不是一个真正有用的概念,无论是 Python 还是 shell。对对象的引用在高级语言中当然很有用,甚至可能是构建复杂数据结构所必需的。但在大多数情况下,根据内存地址进行思考的层次太低,没有多大用处。
在 Bash(和其他 shell)中,您可以使用 符号获取数组元素的值${array[index]}
,使用 对其进行赋值array[index]=...
,并使用 获取数组中的元素数量${#array[@]}
。括号内的表达式是算术表达式。作为一个虚构的例子,我们可以为所有数组成员添加一个常量前缀:
for ((i=0 ; i < ${#array[@]} ; i++ )) ; do
array[i]="foo-${array[i]}"
done
(如果我们只关心值,而不关心索引,那for x in "${array[@]}" ; do...
就没问题了。)
和联想性的或稀疏数组,数字循环没有多大意义,但我们需要使用 来获取数组键/索引${!array[@]}
。例如
declare -A assoc=([foo]="123" [bar]="456")
for i in "${!assoc[@]}" ; do
echo "${assoc[$i]}"
done
除此之外,Bash 有两种方法间接指向另一个变量:
- 间接扩张, 使用语法
${!var}
,它使用变量的值,该变量的值姓名是在var
, 并且 - 名称引用,需要用
declare
内置(或ksh
-兼容同义词,typeset
)。declare -n ref=var
引用ref
变量var
。
Namerefs 还支持索引,因为如果我们有arr=(a b c); declare -n ref=arr;
then${ref[1]}
将扩展到b
.使用${!p[1]}
将p
作为一个数组,并引用由其第二个元素命名的变量。
在 Bash 中,namerefs 的字面意思是,引用姓名,并且在函数内部使用 nameref 将使用指定变量的本地值。这将打印local value of var
.
#!/bin/bash
fun() {
local var="local value of var"
echo "$ref";
}
var="global var"
declare -n ref=var
fun
Bash常见问题解答有关于间接的较长文章, 也。
答案2
不,bash
没有“指针”,但它确实有引用:
$ spam="fred"
$ declare -n tripe=spam
$ echo $tripe
fred
$ tripe=juki
$ echo $spam
juki
从bash
手册页:
declare
可以使用内置命令的 -n 选项来为变量分配 nameref 属性,local
以创建 nameref 或对另一个变量的引用。这允许间接操纵变量。每当 nameref 变量被引用、赋值、取消设置或修改其属性(除了使用或更改 nameref 属性本身)时,实际上都会对 nameref 变量的值指定的变量执行操作。 nameref 通常在 shell 函数中使用来引用其名称作为参数传递给函数的变量。例如,如果将变量名作为第一个参数传递给 shell 函数,则运行declare -n ref=$1
函数内部创建一个 nameref 变量 ref,其值是作为第一个参数传递的变量名称。对 ref 的引用和赋值以及对其属性的更改均被视为对名称作为 $1 传递的变量的引用、赋值和属性修改。如果 for 循环中的控制变量具有 nameref 属性,则单词列表可以是 shell 变量列表,并且在执行循环时将为列表中的每个单词建立名称引用。不能为数组变量赋予 nameref 属性。但是,nameref 变量可以引用数组变量和下标数组变量。可以使用内置的 -n 选项取消设置 Namerefs
unset
。否则,如果unset
使用 nameref 变量的名称作为参数执行,则 nameref 变量引用的变量将被取消设置。
答案3
不,shell 不使用“指针”(如 C 中所理解的)。
数组可以使用索引:echo "${array[2]}"
但是@
您的示例中的 并不是真正的“指针”。它是一种表达“数组值列表”的方式。 shell 解析器可以理解的东西。类似于a的方式:
$ echo "$@"
展开至所有“位置参数”列表。
答案4
虽然 bash 整数索引数组可以像这样定义和迭代访问;
declare -a obj
obj+=("val1")
obj+=("val2")
for item in ${obj[@]}; do
echo "${obj[${item}]} ${item}"
done
bash 中基于关联或字符串的索引数组需要以下迭代定义;
declare -A obj
obj["key1"]="val1"
obj["key2"]="val2"
for item in ${!obj[@]}; do
echo "${obj[${item}]} ${item}"
done
回答有关指针和使用 bash 中的指针的问题;已编译的 bash 二进制文件的内部功能确实使用了指向堆栈上分配的内存的指针,并且确实通过使用eval
.参见[间接引用]http://tldp.org/LDP/abs/html/ivr.html)
有龙;eval
由于安全隐患,应谨慎使用