【问题标题】:Read a config file in BASH without using "source"在 BASH 中读取配置文件而不使用“源”
【发布时间】:2011-05-25 00:04:33
【问题描述】:

我正在尝试读取格式如下的配置文件:

USER = username
TARGET = arrows

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

  1. 将行读入数组
  2. 过滤掉所有以#开头的行
  3. 在数组中搜索变量名

在那之后我迷路了。任何和所有的帮助将不胜感激。我已经尝试过这样的事情但没有成功:

backup2.config>cat ~/1

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

我从我发现的一个论坛帖子中提取了它,只是不确定如何修改它以满足我的需要,因为我对 shell 脚本还很陌生。

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


是否可以通过循环遍历两个数组来自动分配变量?

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

这样调用 $USER 会输出“用户名”吗?上面的代码不起作用,但我知道解决方案与此类似。

【问题讨论】:

    标签: bash grep eval config


    【解决方案1】:

    以下脚本遍历输入文件中的每一行(在我的例子中为 vars)并针对= 进行模式匹配。如果找到等号,它将使用Parameter Expansionvalue 中解析出变量name。然后它将每个部分存储在它自己的数组中,分别是 namevalue

    #!/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[@]}"
    

    输入

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

    输出

    $ ./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
    

    【讨论】:

    • 很好,但您介意解释一下,以便我更好地理解它在做什么吗?
    • 这个解决方案唯一的问题是,即使一行被注释并且有 [CODE] #使用示例 USER = what 来定义这个配置 [/CODE] 那么它将包括“whatever to在 VALUE 数组中定义此配置。
    • @Gerry 脚本的当前迭代应该处理#Use the example USER = whatever 的情况,但如果您有USER = whatever #this is an inline comment,它将无法工作。检查以确保您拥有最新版本,因为我编辑了几次。
    • 要完成这项工作,您必须从正则表达式字符串中删除引号。看看stackoverflow.com/questions/218156/bash-regex-with-quotes
    • @SiegeX,为了匹配配置文件中的 key=value(注意 '=' 符号之前/之后缺少空格)但是如果我们使用表达式:name[i]=${line% %=*} value[i]=${line##*=} 似乎没问题。这样不是更好吗?
    【解决方案2】:

    首先,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"
    

    这会将文件中的变量设置为与其关联的值。

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

    会输出

    用户名:用户名,目标:箭头

    使用键和值的另一种方法是使用关联数组:

    while循环之前添加这一行:

    declare -A settings
    

    删除while 循环内的declare 行并将其替换为:

        settings[$lhs]=$rhs
    

    然后:

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

    会输出

    用户名:用户名,目标:箭头

    【讨论】:

    • $line 是如何/在哪里定义的?
    • 为什么是shopt -s exglob
    • @Koveras:这启用了扩展 glob *(),它匹配零次或多次出现的给定模式(多个模式由 | 分隔)。在这种情况下,零个或多个空格。
    【解决方案3】:

    我有一个脚本,它只需要非常有限数量的设置,并且一次处理一个,所以我调整了 SiegeX 的答案,将我关心的设置列入白名单,并在涉及到它们时对其进行操作。

    我还删除了对 = 周围空格的要求,转而忽略使用 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";
    

    【讨论】:

      【解决方案4】:

      感谢 SiegeX。我认为您提到的后续更新并未反映在此 URL 中。

      我必须编辑正则表达式以删除引号以使其正常工作。带引号,返回的数组为空。

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

      一个更好的版本是。

      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
      

      如果配置文件中“=”前后没有空格,则认为第一个版本存在问题。此外,如果缺少值,我会看到名称和值填充为相同。第二个版本没有这些。此外,它还会修剪掉不需要的前导和尾随空格。

      此版本读取其中可以包含 = 的值。早期版本在第一次出现 = 时拆分。

      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
      

      【讨论】:

        猜你喜欢
        • 2011-07-02
        • 2015-04-02
        • 2021-09-30
        • 1970-01-01
        • 2018-09-15
        • 1970-01-01
        • 2021-01-13
        • 2014-09-21
        • 1970-01-01
        相关资源
        最近更新 更多