开发者

Read a config file in BASH without using "source"

I'm attempting to read a config file that is formatted as follows:

USER = username
TARGET = arrows

I realize that if I got rid of the spaces, I could simply source the config file, but for security reasons I'm trying to avoid that. I know there is a way to read the config file line by line. I think the process is something like:

  1. Read lines into an array
  2. Filter out all of the lines that start with #
  3. search for the variable names in the array

After that I'm lost. Any and all help would be greatly appreciated. I've tried something like this with no success:

backup2.config>cat ~/1

grep '^[^#].*' | while read one two;do
    echo $two
done

I pu开发者_StackOverflow中文版lled that from a forum post I found, just not sure how to modify it to fit my needs since I'm so new to shell scripting.

http://www.linuxquestions.org/questions/programming-9/bash-shell-program-read-a-configuration-file-276852/


Would it be possible to automatically assign a variable by looping through both arrays?

for (( i = 0 ; i < ${#VALUE[@]} ; i++ ))
do
    "${NAME[i]}"=VALUE[i]           
done
echo $USER

Such that calling $USER would output "username"? The above code isn't working but I know the solution is something similar to that.


The following script iterates over each line in your input file (vars in my case) and does a pattern match against =. If the equal sign is found it will use Parameter Expansion to parse out the variable name from the value. It then stores each part in it's own array, name and value respectively.

#!/bin/bash

i=0
while read line; do
  if [[ "$line" =~ ^[^#]*= ]]; then
    name[i]=${line%% =*}
    value[i]=${line#*= }
    ((i++))
  fi
done < vars

echo "total array elements: ${#name[@]}"
echo "name[0]: ${name[0]}"
echo "value[0]: ${value[0]}"
echo "name[1]: ${name[1]}"
echo "value[1]: ${value[1]}"
echo "name array: ${name[@]}"
echo "value array: ${value[@]}"

Input

$ cat vars
sdf
USER = username
TARGET = arrows
asdf
as23

Output

$ ./varscript
total array elements: 2
name[0]: USER
value[0]: username
name[1]: TARGET
value[1]: arrows
name array: USER TARGET
value array: username arrows


First, USER is a shell environment variable, so it might be better if you used something else. Using lowercase or mixed case variable names is a way to avoid name collisions.

#!/bin/bash
configfile="/path/to/file"
shopt -s extglob
while IFS='= ' read lhs rhs
do
    if [[ $lhs != *( )#* ]]
    then
        # you can test for variables to accept or other conditions here
        declare $lhs=$rhs
    fi
done < "$configfile"

This sets the vars in your file to the value associated with it.

echo "Username: $USER, Target: $TARGET"

would output

Username: username, Target: arrows

Another way to do this using keys and values is with an associative array:

Add this line before the while loop:

declare -A settings

Remove the declare line inside the while loop and replace it with:

    settings[$lhs]=$rhs

Then:

# set keys
user=USER
target=TARGET
# access values
echo "Username: ${settings[$user]}, Target: ${settings[$target]}"

would output

Username: username, Target: arrows


I have a script which only takes a very limited number of settings, and processes them one at a time, so I've adapted SiegeX's answer to whitelist the settings I care about and act on them as it comes to them.

I've also removed the requirement for spaces around the = in favour of ignoring any that exist using the trim function from another answer.

function trim()
{
    local var=$1;
    var="${var#"${var%%[![:space:]]*}"}";   # remove leading whitespace characters
    var="${var%"${var##*[![:space:]]}"}";   # remove trailing whitespace characters
    echo -n "$var";
}

while read line; do
    if [[ "$line" =~ ^[^#]*= ]]; then
        setting_name=$(trim "${line%%=*}");
        setting_value=$(trim "${line#*=}");

        case "$setting_name" in
            max_foos)
                prune_foos $setting_value;
            ;;
            max_bars)
                prune_bars $setting_value;
            ;;
            *)
                echo "Unrecognised setting: $setting_name";
            ;;
        esac;
    fi
done <"$config_file";


Thanks SiegeX. I think the later updates you mentioned does not reflect in this URL.

I had to edit the regex to remove the quotes to get it working. With quotes, array returned is empty.

i=0
while read line; do
  if [[ "$line" =~ ^[^#]*= ]]; then
    name[i]=${line%% =*}
    value[i]=${line##*= }
    ((i++))
  fi
 done < vars

A still better version is .

i=0
while read line; do
if [[ "$line" =~ ^[^#]*= ]]; then
        name[i]=`echo $line | cut -d'=' -f 1`
            value[i]=`echo $line | cut -d'=' -f 2`
        ((i++))
fi
done < vars

The first version is seen to have issues if there is no space before and after "=" in the config file. Also if the value is missing, i see that the name and value are populated as same. The second version does not have any of these. In addition it trims out unwanted leading and trailing spaces.

This version reads values that can have = within it. Earlier version splits at first occurance of =.

i=0
while read line; do
if [[ "$line" =~ ^[^#]*= ]]; then
        name[i]=`echo $line | cut -d'=' -f 1`
            value[i]=`echo $line | cut -d'=' -f 2-`
        ((i++))
fi
done < vars
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜