我正在使用循环调用函数for
并将返回值保存到变量中。当我运行代码时,出现command not found
错误。怎么了?
#!/bin/bash
check_1()
{
x_$1=$(check_2 $1)
}
check_2()
{
ans=$((3+$1))
echo $ans
}
for((i=1; i<=2;i++))
do
check_1 $i
tmp=x_$i
echo ${!tmp}
done
如果我运行上面的脚本,我会得到:
sample.sh: line 5: x_1=4: command not found
sample.sh: line 5: x_2=5: command not found
答案1
您不能以这种方式定义变量名称。您试图通过使用另一个变量的值来构建变量的名称:x_$1=foo
这是行不通的。更好的方法是使用数组:
#!/bin/bash
check_1()
{
x[$1]=$(check_2 "$1")
}
check_2()
{
ans=$((3+$1))
echo "$ans"
}
for((i=1; i<=2;i++))
do
check_1 "$i"
echo "${x[$i]}"
done
以上返回:
$ sample.sh
4
5
答案2
你应该,正如特登所说他的回答,请改用 bash 的关联数组。
但是,如果你坚持,并且你有足够新的 bash,你可以使用名称引用(顺便说一下,这是在手册页中搜索的神奇词)。
i=1
declare -n tmp="foo_$i" # this is the nameref line
tmp="fooval" # actually sets $foo_1
echo "$foo_1" # prints fooval
如果在函数内部,请使用local -n
而不是declare -n
获取函数局部变量。
答案3
如果你不只研究数学,我会建议唯一的其他安全/便携我知道一种不需要非常严格测试的方法:
var1=string1
export "$var1=string2"
echo "$var1"
echo "$string1"
输出
string1
string2
但是您只是在处理数学问题,所以您的问题是,echo
当您应该同时在当前 shell 中定义变量并对其进行评估时,您却将变量的值放入子 shell 中。
i=0 ; until [ $((i=$i+1)) -ge 3 ]
do echo "\$x_$i = $((x_$i=3+$i))"
done
echo $x_1 $x_2
输出
$x_1 = 4
$x_2 = 5
4 5
所以你所做的只是数学。 shell 算术的有趣之处在于,您可以使用它安全地对当前 shell 中的变量求值两次 - 没有子 shell。
算术扩展提供了一种计算算术表达式并替换其值的机制。算术展开式的格式如下:
$((expression))
该表达式应被视为位于双引号中,但表达式内的双引号不作特殊处理。 shell 应扩展表达式中的所有标记以进行参数扩展、命令替换和引号删除。
也许更有趣的是,它还有这样的说法:
算术表达式中变量的所有更改都应在算术扩展之后生效,如参数扩展一样
"${x=value}"
。如果 shell 变量
x
包含形成有效整数常量的值(可选地包含前导加号或减号),则算术扩展"$((x))"
和"$(($x))"
应返回相同的值。
因此,如果在算术替换的上下文中定义变量,则该定义将在当前环境中保留。喜欢:
echo $((x=1)); echo $x
1
1
但如果你添加其他部分 - 特别是shell 应展开所有标记 和那"$((x))"
并"$(($x))"
应返回相同的值。您也许能够看到上面的until
循环是如何工作的。
所以:
$((x_ #just a string
$i #integer value
= #assignment operator
3 + #addition
$i )) #same integer value
您会看到 shell 必须$i
在两种上下文中扩展 :变量 shell 标记作为赋值运算符之前的字符串,以及执行加法运算的整数值,其总和被分配给x_$i
。
数组可能很方便,但是,不包括一种形式,它们不可移植,并且都带有自己特定于实现的混乱。此外 - 这是您所问问题的答案。
这就是以下函数起作用的原因:
defv() {
[ -n "${1##*[!0-9]*}" ] && # verify $1 is numeric only
v=x_$1 && # redefine caller loop var
: $((x_$1=5+$1)) # : do nothing but expand arg
}
for v in 1 2 3 4 5 # init array
do defv $v # defv() $indirection
echo "$v = $(($v))" # \$x_$indirection = $x_$indirection
done
输出
x_1 = 6
x_2 = 7
x_3 = 8
x_4 = 9
x_5 = 10
您的职能:
check_1()
{
check_2 x_$1 $1
}
check_2()
{
: $(($1=3+$2))
}
for((i=1; i<=2;i++))
do
check_1 $i
tmp=x_$i
echo ${!tmp}
done
输出
4
5