如何在shell脚本中即时生成新的variables名称?

我试图在一个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名称?

Solutions Collecting From Web of "如何在shell脚本中即时生成新的variables名称?"

您需要使用变量间接:

 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 ,这就是为什么你得到了你所做的结果。

解决问题的方法

有两个主要的方法来解决这个问题:

  1. 插值变量的多级解引用,通过eval内建或间接变量扩展 。
  2. 迭代一个数组,或者使用i作为数组的索引。

eval解引用

在这种情况下最容易做的就是使用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的值附加到变量末尾,然后重新处理结果行,扩展插入的变量名称(例如SAMPLE1SAMPLE2 )。

用间接变量解引用

这个问题被接受的答案是:

 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 

这比其他方法增加了好处。 特别:

  1. 您不需要指定复杂的循环测试。
  2. 您可以通过$ SAMPLE [$ i]语法访问各个数组元素。
  3. 您可以使用$ {#SAMPLE}变量扩展来获取元素的总数。

实例的实际等价性

这三种方法都适用于原始问题中的示例,但是数组解决方案提供了最大的灵活性。 选择哪一个最适合您手边的数据。

您可以使用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