我正在尝试在shell脚本中生成动态var名称,以便在循环中处理一组具有不同名称的文件,如下所示:
#!/bin/bash
SAMPLE1='1-first.with.custom.name'
SAMPLE2='2-second.with.custom.name'
for (( i = 1; i <= 2; i++ ))
do
echo SAMPLE{$i}
done
我希望输出:
1-first.with.custom.name
2-second.with.custom.name
但我得到了:
SAMPLE{1}
SAMPLE{2}
是否有可能在飞行中生成var名称?
答案 0 :(得分:65)
您需要使用变量间接:
SAMPLE1='1-first.with.custom.name'
SAMPLE2='2-second.with.custom.name'
for (( i = 1; i <= 2; i++ ))
do
var="SAMPLE$i"
echo ${!var}
done
来自Bash man page,在'参数扩展'下:
“如果参数的第一个字符是感叹号(!),则a 引入了变量间接的级别。 Bash使用的值 由参数的其余部分形成的变量作为名称 变量;然后展开此变量,并在该变量中使用该值 其余的替换,而不是参数本身的值。 这被称为间接扩张。“
答案 1 :(得分:17)
您正在使用 i 的值,就好像它是一个数组索引一样。它不是,因为SAMPLE1和SAMPLE2是单独的变量,而不是数组。
此外,在调用echo SAMPLE{$i}
时,您只需将 i 的值附加到单词“SAMPLE”。您在此声明中解除引用的唯一变量是 $ i ,这就是您获得结果的原因。
有两种主要方法可以解决这个问题:
在这种情况下最简单的方法是使用 eval :
SAMPLE1='1-first.with.custom.name'
SAMPLE2='2-second.with.custom.name'
for (( i = 1; i <= 2; i++ )); do
eval echo \$SAMPLE${i}
done
这会将 i 的值附加到变量的末尾,然后重新处理结果行,展开插值变量名称(例如 SAMPLE1 或 SAMPLE2 )。
这个问题的答案是:
SAMPLE1='1-first.with.custom.name'
SAMPLE2='2-second.with.custom.name'
for (( i = 1; i <= 2; i++ ))
do
var="SAMPLE$i"
echo ${!var}
done
这在技术上是一个三步过程。首先,它将插值变量名称分配给 var ,然后取消引用存储在 var 中的变量名称,最后展开结果。它看起来有点干净,有些人比使用 eval 更熟悉这种语法,但结果基本相同。
您可以通过迭代数组而不是使用变量插值来简化循环和扩展。例如:
SAMPLE=('1-first.with.custom.name' '2-second.with.custom.name')
for i in "${SAMPLE[@]}"; do
echo "$i"
done
这比其他方法增加了好处。具体做法是:
这三种方法都适用于原始问题中给出的示例,但阵列解决方案提供了最大的整体灵活性。选择最适合您手头数据的那个。
答案 2 :(得分:3)
据我所知,他们的方式@ johnshen64说。此外,您可以使用如下数组来解决您的问题:
SAMPLE[1]='1-first.with.custom.name'
SAMPLE[2]='2-second.with.custom.name'
for (( i = 1; i <= 2; i++ )) do
echo ${SAMPLE[$i]}
done
请注意,您不需要使用数字,因为索引SAMPLE[hello]
也可以正常工作
答案 3 :(得分:3)
您可以使用eval
,如下所示:
SAMPLE1='1-first.with.custom.name'
SAMPLE2='2-second.with.custom.name'
for (( i = 1; i <= 2; i++ ))
do
eval echo \$SAMPLE$i
done
答案 4 :(得分:2)
不是一个独立的答案,只是对Miquel的答案的补充,我不能很好地评论。
您可以使用循环,+ =运算符和here文档填充数组:
SAMPLE=()
while read; do SAMPLE+=("$REPLY"); done <<EOF
1-first.with.custom.name
2-second.with.custom.name
EOF
在bash 4.0中,它就像
一样简单readarray SAMPLE <<EOF
1-first.with.custom.name
2-second.with.custom.name
EOF
答案 5 :(得分:0)
eval "echo $SAMPLE${i}"