在bash中读取配置文件的最佳方法


23

在bash中读取配置文件的最佳方法是什么?
例如,您有一个脚本,并且不愿意在每次调用该脚本时手动填写所有配置。

编辑1:我想我没有说清楚,所以:我想要的是...我有一个像

variable_name value  
variable_name value ...  

我想读一读。我知道我可以将其grep表示我正在寻找的参数...但是也许有一种更聪明的方法:)


2
您必须显示您的意思是哪种配置。提供一个例子。
muru

另请参见Unix和Linux StackExchange上的一个非常类似的问题
迈克尔

Answers:


38

正如mbiber所说的,source另一个文件。例如,您的配置文件(例如some.config)将是:

var1=val1
var2=val2

您的脚本可能如下所示:

#! /bin/bash

# Optionally, set default values
# var1="default value for var1"
# var1="default value for var2"

. /path/to/some.config

echo "$var1" "$var2"

/etc/default通常,许多文件以类似的方式用作其他Shell脚本的配置文件。这里的帖子中一个非常常见的示例是/etc/default/grub。该文件用于设置GRUB的配置选项,因为它grub-mkconfig是提供该文件的Shell脚本:

sysconfdir="/etc"
#…
if test -f ${sysconfdir}/default/grub ; then
  . ${sysconfdir}/default/grub
fi

如果您确实必须处理表单的配置:

var1 some value 1
var2 some value 2

然后,您可以执行以下操作:

while read var value
do
    export "$var"="$value"
done < /path/to/some.config

(您也可以执行类似的操作eval "$var=$value",但这比采购脚本要冒险。与源文件相比,您可能无意间破坏了该文件。)


那是一个很棒的方法,我可以使用sed替代空格代替“ =”
IcyIcyIce

1
@IcyIcyIce只是不要。为什么=从一开始就不能编写它?
muru

1
@IcyIcyIce就是这样。您可以在/etc/default- 的各种文件中使用shell代码-并充分利用。如果您的笨拙用户可以访问以root身份运行的某些东西的配置,那么这已经是一个失败的原因。
大师

1
@IcyIcyIce让您的老师阐明他们想要什么。学习开发软件的一部分就是清楚地了解需求。
muru

1
@IcyIcyIce请参阅更新。
muru

4

显然,我不是bash这里的专家,但是无论您使用哪种语言,概念都不应有所不同:

一个例子

在下面的示例中,您可以使用(非常)基本的脚本来按照配置文件中的设置设置字符串或打印字符串:

#!/bin/bash

# argument to set a new string or print the set string
arg=$1
# possible string as second argument
string=$2
# path to your config file
configfile="$HOME/stringfile"

# if the argument is: "set", write the string (second argument) to a file
if [ "$arg" == "set" ]
then
echo "$string" > $configfile 
# if the argunment is "print": print out the set string, as defined in your file
elif [ "$arg" == "print" ]
then 
echo "$( cat $configfile )"
fi

然后

  • 要将字符串设置到您的配置文件中:

    $ '/home/jacob/Bureaublad/test.sh' set "Een aap op een fiets, hoe vind je zoiets?"
  • 随后,按照“ configfile”中的定义打印出字符串:

    $ '/home/jacob/Bureaublad/test.sh' print
    Een aap op een fiets, hoe vind je zoiets?

当然,在实际应用的脚本中,您需要添加很多内容以确保参数正确,确定输入不正确,设置文件不存在时的处理方法等,但是:

这是基本思路


谢谢,我只是在更新我认为我没有说清楚的问题...但是在简单的情况下,这就像一个魅力
办公室

4

使用source.加载文件。

source /path/to/file

要么

. /path/to/file

还建议您在加载文件之前检查文件是否存在,因为如果不存在配置文件,您不想继续运行脚本。


0

我正在使用这个...

#!/bin/bash

CFG_FILE=/etc/test.conf
CFG_CONTENT=$(cat $CFG_FILE | sed -r '/[^=]+=[^=]+/!d' | sed -r 's/\s+=\s/=/g')
eval "$CFG_CONTENT"

Conf文件用sed解析,然后评估为简单变量赋值

sed首先解析键值(也支持=包含空格)

第二个sed删除=号周围的空格,以表示有效的变量分配

可以添加进一步的治疗

conf文件中所有其他不匹配的文本将被删除(包括#或;注释和其他)

请注意,也可以从此配置文件评估单行外壳命令!


1
没用的cat。为什么您sed要背对背调用两次?您可以sed像这样链接命令:sed -r '/[^=]+=[^=]+/!d;s/\s+=\s/=/g'
David Foerster

同样,此sed命令将为问题中的示例配置文件条目生成一个空输出。-1
David Foerster

1
另一个可能的改进:使用.命令和进程重定向而不是临时变量来保存子进程的输出:. <(sed ... "$CFG_FILE")
David Foerster

当然,我的示例使用key = value这样的配置文件。比“键值”更好的做法。使用key = value我的示例有效。我承认,您将sed命令链接起来更好,但是源命令需要文件,因此我们可以使用:eval $(sed -r '/[^=]+=[^=]+/!d;s/\s+=\s/=/g' "$CFG_FILE"),这样可以更好地了解正在发生的情况。
smARTin

是的,.期望将文件和进程替换扩展为文件。. <(echo echo foo)可以按照Bash v4.3.11中的预期工作。在较小的示例中,这可能无关紧要。我宁愿不要通过命令替换传递多个千字节。
David Foerster

0
#------------------------------------------------------------------------------
# parse the ini like $0.$host_name.cnf and set the variables
# cleans the unneeded during after run-time stuff. Note the MainSection
# courtesy of : http://mark.aufflick.com/blog/2007/11/08/parsing-ini-files-with-sed
#------------------------------------------------------------------------------
doParseConfFile(){
    # set a default cnfiguration file
    cnf_file="$run_unit_bash_dir/$run_unit.cnf"

    # however if there is a host dependant cnf file override it
    test -f "$run_unit_bash_dir/$run_unit.$host_name.cnf" \
    && cnf_file="$run_unit_bash_dir/$run_unit.$host_name.cnf"

    # yet finally override if passed as argument to this function
    # if the the ini file is not passed define the default host independant ini file
    test -z "$1" || cnf_file=$1;shift 1;


    test -z "$2" || ini_section=$2;shift 1;
    doLog "DEBUG read configuration file : $cnf_file"
    doLog "INFO read [$ini_section] section from config file"

    # debug echo "@doParseConfFile cnf_file:: $cnf_file"
    # coud be later on parametrized ...
    test -z "$ini_section" && ini_section='MAIN_SETTINGS'

    doLog "DEBUG reading: the following configuration file"
    doLog "DEBUG ""$cnf_file"
    ( set -o posix ; set ) | sort >"$tmp_dir/vars.before"

    eval `sed -e 's/[[:space:]]*\=[[:space:]]*/=/g' \
        -e 's/#.*$//' \
        -e 's/[[:space:]]*$//' \
        -e 's/^[[:space:]]*//' \
        -e "s/^\(.*\)=\([^\"']*\)$/\1=\"\2\"/" \
        < $cnf_file \
        | sed -n -e "/^\[$ini_section\]/,/^\s*\[/{/^[^#].*\=.*/p;}"`

    ( set -o posix ; set ) | sort >"$tmp_dir/vars.after"

    doLog "INFO added the following vars from section: [$ini_section]"
    cmd="$(comm -3 $tmp_dir/vars.before $tmp_dir/vars.after | perl -ne 's#\s+##g;print "\n $_ "' )"
    echo -e "$cmd"
    echo -e "$cmd" >> $log_file
    echo -e "\n\n"
    sleep 1; printf "\033[2J";printf "\033[0;0H" # and clear the screen
}
#eof func doParseConfFile
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.