在不使用“源”的情况下在 BASH 中读取配置文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4434797/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Read a config file in BASH without using "source"
提问by Gerry
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:
我意识到如果我摆脱了空格,我可以简单地获取配置文件,但出于安全原因,我试图避免这种情况。我知道有一种方法可以逐行读取配置文件。我认为这个过程是这样的:
- Read lines into an array
- Filter out all of the lines that start with #
- 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 pulled 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.
我从我发现的论坛帖子中提取了它,只是不确定如何修改它以满足我的需求,因为我对 shell 脚本很陌生。
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.
这样调用 $USER 会输出“用户名”?上面的代码不起作用,但我知道解决方案与此类似。
采纳答案by SiegeX
The following script iterates over each line in your input file (varsin my case) and does a pattern match against =. If the equal sign is found it will use Parameter Expansionto parse out the variable namefrom the value. It then stores each part in it's own array, nameand valuerespectively.
以下脚本遍历输入文件中的每一行(在我的情况下为vars),并针对=. 如果找到等号,它将使用参数扩展从值中解析出变量名称。然后它将每个部分分别存储在它自己的数组、名称和值中。
#!/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
回答by Paused until further notice.
First, USERis 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.
首先,USER是一个shell环境变量,所以如果你用别的东西可能会更好。使用小写或大小写混合的变量名是避免名称冲突的一种方法。
#!/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 whileloop:
在while循环之前添加这一行:
declare -A settings
Remove the declareline inside the whileloop and replace it with:
删除循环declare内的行while并将其替换为:
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
用户名:用户名,目标:箭头
回答by IMSoP
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.
我有一个脚本,它只需要非常有限数量的设置,并且一次处理它们,所以我调整了 SiegeX 的答案,将我关心的设置列入白名单,并在遇到这些设置时对其采取行动。
I've also removed the requirement for spaces around the =in favour of ignoring any that exist using the trimfunction from another answer.
我还删除了对周围空间的要求,=以支持忽略使用另一个答案中的trim函数存在的任何空间。
function trim()
{
local var=;
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";
回答by Sibi JV
Thanks SiegeX. I think the later updates you mentioned does not reflect in this URL.
感谢 SiegeX。我认为您提到的后期更新并未反映在此 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

