如何在shell脚本中动态生成新的变量名?

pQB*_*pQB 38 linux bash shell

我正在尝试在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
Run Code Online (Sandbox Code Playgroud)

我期待输出:

1-first.with.custom.name
2-second.with.custom.name
Run Code Online (Sandbox Code Playgroud)

但我得到了:

SAMPLE{1}
SAMPLE{2}
Run Code Online (Sandbox Code Playgroud)

是否有可能在飞行中生成var名称?

joh*_*n64 69

您需要使用变量间接:

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
Run Code Online (Sandbox Code Playgroud)

Bash手册页的 "参数扩展"下:

"如果参数的第一个字符是感叹号(!),则引入一个变量间接的级别.Bash使用从参数的其余部分形成的变量的值作为变量的名称;然后扩展该变量并且value用于替换的其余部分,而不是参数本身的值.这称为间接扩展."

  • 在Bash手册页中查看参数扩展.对于`$ {parameter}`:"如果参数的第一个字符是感叹号(!),则引入一个变量间接的级别.Bash使用从参数的其余部分形成的变量的值作为变量的名称;然后展开这个变量,并在替换的其余部分使用该值,而不是参数本身的值.这称为间接扩展." (11认同)

Tod*_*obs 18

问题

您正在使用i的值,就好像它是一个数组索引一样.它不是,因为SAMPLE1和SAMPLE2是单独的变量,而不是数组.

此外,在呼叫时,echo SAMPLE{$i}您只将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
Run Code Online (Sandbox Code Playgroud)

这会将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
Run Code Online (Sandbox Code Playgroud)

这在技术上是一个三步过程.首先,它为var分配一个插值变量名,然后取消引用存储在var中的变量名,最后展开结果.它看起来有点干净,有些人对这种语法比使用eval更舒服,但结果基本相同.

迭代数组

您可以通过迭代数组而不是使用变量插值来简化循环和扩展.例如:

SAMPLE=('1-first.with.custom.name' '2-second.with.custom.name')
for i in "${SAMPLE[@]}"; do
    echo "$i"
done
Run Code Online (Sandbox Code Playgroud)

与其他方法相比,这增加了优势.特别:

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

原始实例的实际等效性

所有这三种方法都适用于原始问题中给出的示例,但阵列解决方案提供了最大的整体灵活性.选择最适合您手头数据的那个.

  • 如果您对此用例感到强烈,请随时指出eval与此用例**的间接变量**的区别.然而,很多人反复避免eval,即使它是适合工作的工具 - 如果你可以信任你的输入源,你可以信任eval.在每篇关于eval潜在恶言的帖子中添加免责声明有点像那些无处不在的标签上写着"警告:这种咖啡可能很热". (4认同)
  • 在所有3个解决方案中,eval是唯一一个在灰中工作的解决方案.答案为+1.如果你不应该使用命令,它就不会存在. (2认同)