Bash:根据文件名动态创建具有变量名称的变量

Bash: Dynamically create variables with the variable name based on a filename

提问人:nooblag 提问时间:8/10/2023 更新时间:8/10/2023 访问量:117

问:

这个问题来自于减少 bash 脚本中一些重复的愿望,即检查文件中是否有内容,如果有,则将其第一行加载到同名变量中。

目前,对于贯穿始终的每个变量,都有几行这样的行:

[[ -s './config/foo' ]] && read -r foo < './config/foo' || echo "problem with ./config/foo file"
[[ -s './config/bar' ]] && read -r foo < './config/bar' || echo "problem with ./config/foo file"

但是,与其经历太多这样的行,我想我也许可以通过使用数组来自动化这个过程(稍后,也可以用这种方法扩展到其他测试)。

因此,我从下面的代码开始,但想知道是否可以动态创建变量名称?我不知道该怎么做,也不知道这是否可能。我知道我可以通过去除路径来获取我们想要用于创建变量名称的文件的名称(例如,因此成为),但是如何将该结果转换为变量名称,然后将其设置为文件第一行的内容,就像原始脚本一样?${file##*/}./config/foofoo

这是我到目前为止所拥有的,我们可以从哪里得到这个名字:DYNAMIC_VARIABLE_NAME_HERE${file##*/}

#!/bin/bash

# check and load config files
required_files=(
  './config/foo'
  './config/bar'
)
for file in "${required_files[@]}"; do
  [[ -s "${file}" ]] && read -r DYNAMIC_VARIABLE_NAME_HERE < "${file}" || failed+=("${file}")
done
if [[ ${#failed[@]} -ne 0 ]]; then
  echo "there is a problem with the following configuration files:"
  for file in "${failed[@]}"; do
    echo "${file}"
  done
fi

# check
echo "foo: ${foo}"
echo "bar: ${bar}"

到目前为止的输出

foo:
bar:

所需输出

foo: [first line of ./config/foo file]
bar: [first line of ./config/bar file]
数组 bash 变量 动态

评论

2赞 Barmar 8/10/2023
这是可能的,但如果您可以使用关联数组,为什么要这样做呢?
0赞 nooblag 8/10/2023
感谢您的评论。不幸的是,你可能需要帮助我理解你的意思......不好意思!有没有不同的方法可以达到相同的结果?我当然对这种:)持开放态度
1赞 Barmar 8/10/2023
你在问题中说过:“我想我也许可以通过使用数组来自动化这个过程”。因此,只需使用数组而不是动态变量即可。array[$file]
0赞 shellter 8/10/2023
也许会对你有所帮助(就在循环的顶部,然后引用它而不是.或者我不明白你的要求。祝你好运!mytFileToProcess=${file##*/}for$file
3赞 pjh 8/10/2023
参见 BashFAQ/006(如何使用变量变量(间接变量、指针、引用)或关联数组?

答:

4赞 markp-fuso 8/10/2023 #1

设置:

$ head foo bar
==> foo <==
1st line from foo
2nd line from foo

==> bar <==
1st line from bar
2nd line from bar

如果使用,您可以使用 nameref,例如:bash 4.2+

for fname in foo bar
do
    declare -n curr_var="${fname}"             # nameref
    read -r curr_var < "${fname}"
done

这将生成:

$ typeset -p foo bar
declare -- foo="1st line from foo"
declare -- bar="1st line from bar"

这种方法的一个问题是......如何跟踪动态生成的变量名称。在这种情况下,我们已经在代码中对变量名称进行了硬编码,但是如果有 10 个文件,并且我们事先(以编程方式)不知道文件/变量名称是什么怎么办......您如何/在哪里跟踪变量名称?foobar


使用关联数组的不同方法:

unset      myvar                               # insure array name not in use
declare -A myvar                               # define Associative array

for fname in *                                 # for now assume this matches on files "foo" and "bar"
do
    read -r myvar[$fname] < "${fname}"
done

这将生成:

$ typeset -p myvar
declare -A myvar=([bar]="1st line from bar" [foo]="1st line from foo" )

此外,我们可以通过仔细阅读数组的索引来获得变量名称的列表,例如:

for varname in "${!myvar[@]}"                  # loop through array indices
do
    echo "varname = ${varname} : contents: ${myvar[$varname]}"
done

这将生成:

varname = bar : contents: 1st line from bar
varname = foo : contents: 1st line from foo

评论

2赞 nooblag 8/10/2023
伟大!我认为关联数组方法看起来更干净、更易于管理。感谢您的见解!