Read a config file in BASH without using "source"
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/bashi=0while read line; do if [[ "$line" =~ ^[^#]*= ]]; then name[i]=${line%% =*} value[i]=${line#*= } ((i++)) fidone < varsecho "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 varssdfUSER = usernameTARGET = arrowsasdfas23
Output
$ ./varscripttotal array elements: 2name[0]: USERvalue[0]: usernamename[1]: TARGETvalue[1]: arrowsname array: USER TARGETvalue 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/bashconfigfile="/path/to/file"shopt -s extglobwhile IFS='= ' read lhs rhsdo if [[ $lhs != *( )#* ]] then # you can test for variables to accept or other conditions here declare $lhs=$rhs fidone < "$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 keysuser=USERtarget=TARGET# access valuesecho "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; fidone <"$config_file";