调用一个函数,该函数通过 for 循环调用另一个函数

调用一个函数,该函数通过 for 循环调用另一个函数

我正在使用循环调用函数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。

POSIX 有这样的说法:

算术扩展提供了一种计算算术表达式并替换其值的机制。算术展开式的格式如下:

$((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

相关内容