Bash:根据文件名动态创建变量,其变量名

问题描述 投票:0回答:1

这个问题来自于减少 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/foo
变为
foo
),但是如何将该结果转换为一个变量名,然后将其设置为文件第一行的内容,就像原始脚本一样?

这是我到目前为止所得到的,其中

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]
arrays bash variables dynamic
1个回答
0
投票

设置:

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

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

如果使用

bash 4.2+
,您可以使用名称引用,例如:

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

这会生成:

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

这种方法的一个问题是……如何跟踪动态生成的变量名称。在本例中,我们在代码中硬编码了变量名称

foo
bar
,但是如果有 10 个文件怎么办……如何/在哪里跟踪变量名称?


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

declare -A myvar

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[@]}"
do
    echo "varname = ${varname} : contents: ${myvar[$ndx]}"
done

这会生成:

varname = bar : contents: 1st line from foo
varname = foo : contents: 1st line from foo
© www.soinside.com 2019 - 2024. All rights reserved.