Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
293 views
in Technique[技术] by (71.8m points)

Bash loop dynamic variable from source file

I got a config file called user.conf that contains this list:

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

Notice that user can comment out that line USER2_USERNAME so, only 4 users are used in source file in bash script test.sh here:

#!/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

I want to display which variable is set with its value and skip the commented variables but at this point my code just display an error:

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

Is it possible to loop that variable like above?

Also, user can define much more USER in that user.conf, for example

USER6_USERNAME="George "

Expected output:

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
question from:https://stackoverflow.com/questions/65873108/bash-loop-dynamic-variable-from-source-file

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You can use bash variable substitution like this:

#!/usr/bin/env bash

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

Like your code, this first sources the users file, as it looks like a bash script. This of course has the potentially dangerous side effect that any other code in user.conf runs as well, so be careful and don't let strangers modify that file.

Then it uses ${!var@}, which expands to the names of variables whose names begin with a prefix, here "var", or for you "USER". You could also use ${!var*}, depending on whether you want all values in one quoted variable or multiple ones. See shell parameter expansion for details.

The whole approach is tied to a common prefix for your config variables. In this case, you'll also see $USER in the output, which is the name of the currently logged in user. You can filter that with e.g., grep or a simple if [ "$i" != "USER" ] in the loop.


If you want undefined variables as well, sourcing the users file may not be a good solution. You could instead read the file line by line and check for a leading #:

#!/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

Output:

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"

However, this approach is brittle as it doesn't understand bash syntax. A leading space would be fine when sourcing, but would trip the comment detection on this code. Variables in user names would not get expanded, which may or may not be a good thing.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...