在不使用“源”的情况下在 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 23:05:34  来源:igfitidea点击:

Read a config file in BASH without using "source"

bashgrepevalconfig

提问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:

我意识到如果我摆脱了空格,我可以简单地获取配置文件,但出于安全原因,我试图避免这种情况。我知道有一种方法可以逐行读取配置文件。我认为这个过程是这样的:

  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
  1. 将行读入数组
  2. 过滤掉所有以#开头的行
  3. 在数组中搜索变量名

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 脚本很陌生。

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

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.

这样调用 $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