首页 > 解决方案 > 来自源文件的 Bash 循环动态变量

问题描述

我有一个名为的配置文件user.conf,其中包含此列表:

USER1_USERNAME="John"
#USER2_USERNAME="Mike"
USER3_USERNAME="David"
USER4_USERNAME="James"
USER5_USERNAME="Jenny"

请注意,用户可以注释掉该行USER2_USERNAME,因此 bash 脚本的源文件中只使用了 4 个用户test.sh

#!/bin/bash

#source the username
source "user.conf"

n=1
 while :; do
   ((n++))
   if [ -n "${USER${n}_USERNAME}"]; then
     echo "This variable USER${n}_USERNAME is set: ${USER${n}_USERNAME}"
   else
     echo "This variable USER${n}_USERNAME is not set"
   fi
done

我想显示哪个变量设置了它的值并跳过注释变量,但此时我的代码只显示一个错误:

./test.sh: line 8: ${USER${n}_USERNAME}: bad substitution

是否可以像上面那样循环该变量?

USER此外,用户可以在其中定义更多user.conf,例如

USER6_USERNAME="George "

预期输出:

This variable USER1_USERNAME is set to John
This variable USER2_USERNAME is not set
This variable USER3_USERNAME is set to David
This variable USER4_USERNAME is set to James
This variable USER5_USERNAME is set to Jenny

标签: bash

解决方案


您可以像这样使用 bash 变量替换:

#!/usr/bin/env bash

source "user.conf"
for i in "${!USER@}"
do
    echo $i ${!i}
done

像您的代码一样,这首先获取用户文件,因为它看起来像一个 bash 脚本。这当然有潜在危险的副作用,user.conf 中的任何其他代码也会运行,所以要小心,不要让陌生人修改该文件。

然后它使用${!var@},它扩展为名称以前缀开头的变量的名称,此处为“var”,或者为您提供“USER”。您也可以使用${!var*},这取决于您是想要一个引用变量还是多个变量中的所有值。有关详细信息,请参阅shell 参数扩展

整个方法与配置变量的公共前缀相关联。在这种情况下,您还将$USER在输出中看到当前登录用户的名称。您可以使用例如grep或简单if [ "$i" != "USER" ]的循环过滤它。


如果您还想要未定义的变量,则获取用户文件可能不是一个好的解决方案。您可以改为逐行读取文件并检查前导#

#!/usr/bin/env bash

set -eu

while IFS= read -r line
do
    var=$(echo "$line" | cut -d '=' -f 1)
    name=$(echo "$line" | cut -d '=' -f 2)
    if [[ "$var" =~ ^# ]]
    then
        var=$(echo "$var" | cut -c 2-)
        echo "The variable $var is not set"
    else
        echo "The variable $var is set to $name"
    fi
done

输出:

bash users.sh < users.conf 
The variable USER1_USERNAME is set to "John"
The variable USER2_USERNAME is not set
The variable USER3_USERNAME is set to "David"
The variable USER4_USERNAME is set to "James"
The variable USER5_USERNAME is set to "Jenny"

但是,这种方法很脆弱,因为它不理解 bash 语法。采购时可以使用前导空格,但会触发此代码的注释检测。用户名中的变量不会被扩展,这可能是也可能不是一件好事。


推荐阅读