我试图在一个shell脚本中生成dynamic的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名称?
您需要使用变量间接:
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手册页面的 “参数扩展”下:
“如果参数的第一个字符是感叹号(!),则引入一个变量间接级别,Bash使用由其余参数形成的变量的值作为变量的名称;然后这个变量被扩展,价值是用在其余的替代,而不是参数本身的价值,这就是所谓的间接扩张。
你正在使用我的值,就好像它是一个数组索引。 这不是,因为SAMPLE1和SAMPLE2是单独的变量,而不是一个数组。
另外,在调用echo SAMPLE{$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
这比其他方法增加了好处。 特别:
这三种方法都适用于原始问题中的示例,但是数组解决方案提供了最大的灵活性。 选择哪一个最适合您手边的数据。
您可以使用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
据我所知,他们的方式@ 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]
也可以正常工作
不是一个独立的答案,只是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