shell 读配置文件

摘要:
今天跟同事探讨了一下shell脚本中对配置文件的读写问题。大多数的配置文件都是以key=value形式存在的。为防止这样的情况出现,还是换另一种写法比较安全:shaoqiu@shaoqiu-HP440:~/project/shell$catuser.confid=1name=shaoqiuphone=1234567890shaoqiu@shaoqiu-HP440:~/project/shell$catsetup.sh#!/bin/bashfunctionget_config(){localconfigPath=$1localconfigName=$2sed-n's/^[[:space:]]*'$configName'[[:space:]]*=[[:space:]]*$/1/p'$configPath}functionset_config(){localconfigPath=$1localconfigName=$2localconfgValue=$3sed-i's/^[[:space:]]*'$configName'[[:space:]]*=.*/'$configName'='$confgValue'/g'$configPath}get_configuser.confnameset_configuser.confnameqiushaoget_configuser.confnameshaoqiu@shaoqiu-HP440:~/project/shell$./setup.shshaoqiuqiushaoshaoqiu@shaoqiu-HP440:~/project/shell$catuser.confid=1name=qiushaophone=1234567890shaoqiu@shaoqiu-HP440:~/project/shell$3.section配置文件读取假如配置文件是由多个section组成的呢,就像下面这样:[id=1]name=shaoqiuphone=1234567890[id=2]name=shaojiangphone=5678901234[id=3]name=zhaotongphone=8901234567需要根据输入的id来读写相应的配置项。遇到这种情况,可以使用下面这种方法,将配置文件拆分成多个,分别存放到不同的目录中:config-id1-user.conf-id2-user.conf-id3-user.conf根据id读取不同目录下的配置文件即可。

今天跟同事探讨了一下 shell 脚本中对配置文件的读写问题。在此总结一下常用的配置文件的读写方式。
大多数的配置文件都是以key=value形式存在的。配置项完全由键值对组成。这样的配置文件读写也是最简单的,假如有以下配置文件user.conf

id=1
name=shaoqiu
phone=1234567890

1. source

配置的读取很简单,只要将其source进来即可:

shaoqiu@shaoqiu-HP440:~/project/shell$ cat setup.sh 
#!/bin/bash
source user.conf
echo "id = $id"
echo "name = $name"
echo "phone = $phone"
shaoqiu@shaoqiu-HP440:~/project/shell$ ./setup.sh 
id = 1
name = shaoqiu
phone = 1234567890
shaoqiu@shaoqiu-HP440:~/project/shell$

2. sed

上面的方法看似简单,但可能会有问题,shell的赋值语句=号两边是不能有空格的,万一用户不小心多加了空白符呢。为防止这样的情况出现,还是换另一种写法比较安全:

shaoqiu@shaoqiu-HP440:~/project/shell$ cat user.conf 
id=1
name=shaoqiu
phone=1234567890
shaoqiu@shaoqiu-HP440:~/project/shell$ cat setup.sh 
#!/bin/bash
function get_config() {
    local configPath=$1
    local configName=$2
    sed -n 's/^[[:space:]]*'$configName'[[:space:]]*=[[:space:]]*(.*[^[:space:]])([[:space:]]*)$/1/p' $configPath
}
function set_config() {
    local configPath=$1
    local configName=$2
    local confgValue=$3
    sed -i 's/^[[:space:]]*'$configName'[[:space:]]*=.*/'$configName'='$confgValue'/g' $configPath
}
get_config user.conf name
set_config user.conf name qiushao
get_config user.conf name
shaoqiu@shaoqiu-HP440:~/project/shell$ ./setup.sh 
shaoqiu
qiushao
shaoqiu@shaoqiu-HP440:~/project/shell$ cat user.conf 
id=1
name=qiushao
phone=1234567890
shaoqiu@shaoqiu-HP440:~/project/shell$

3. section 配置文件读取

假如配置文件是由多个section组成的呢,就像下面这样:

[id=1]
name=shaoqiu
phone=1234567890
[id=2]
name=shaojiang
phone=5678901234
[id=3]
name=zhaotong
phone=8901234567

需要根据输入的id来读写相应的配置项。这样就不能简单的使用前面介绍的方法了。遇到这种情况,可以使用下面这种方法,将配置文件拆分成多个,分别存放到不同的目录中:

config
    -id1
        -user.conf
    -id2
        -user.conf
    -id3
        -user.conf

根据id读取不同目录下的配置文件即可。如果配置信息很多的话,推荐使用这种方法,目前在82平台上的机型配置就是使用这种方法来实现的。但若是配置信息很少,且可能有其他脚本也使用到了这个配置文件的时候,拆分配置文件可能就行不通了,需要寻找其他方法。要读写这种格式的配置文件比较复杂,下面是我使用的方法:

shaoqiu@shaoqiu-HP440:~/project/shell$ cat user.conf 
[id=1]
name=shaoqiu
phone=1234567890
[id=2]
name=shaojiang
phone=5678901234
[id=3]
name=zhaotong
phone=8901234567
shaoqiu@shaoqiu-HP440:~/project/shell$ cat setup.sh 
#!/bin/bash
function string_trim()
{
    echo "$1" | sed 's/^[[:space:]]*(.*[^[:space:]])([[:space:]]*)$/1/g'
}
function get_region() {
    local configPath=$1
    local userID=$2
    cat -n $configPath | grep "\[id=.*\]" | grep -A 1 "\[id=$userID\]" | awk '{print $1}' | xargs
}
function get_config() {
    local configPath=$1
    local userID=$2
    local configName=$3
    local region=$(get_region $configPath $userID)
    local startLine=$(echo $region | awk '{print $1}')
    local endLine=$(echo $region | awk '{print $2}')
    string_trim $(sed -n "${startLine}, ${endLine} s/(${configName}.*=.*)/1/p" $configPath | awk -F= '{print $2}')
}
function set_config() {
    local configPath=$1
    local userID=$2
    local configName=$3
    local confgValue=$4
    local region=$(get_region $configPath $userID)
    local startLine=$(echo $region | awk '{print $1}')
    local endLine=$(echo $region | awk '{print $2}')
    sed -i "${startLine}, ${endLine} s/${configName}.*=.*/${configName}=${confgValue}/g" $configPath
}
get_config user.conf 2 name
set_config user.conf 2 name qiushao
get_config user.conf 2 name
shaoqiu@shaoqiu-HP440:~/project/shell$ ./setup.sh 
shaojiang
qiushao
shaoqiu@shaoqiu-HP440:~/project/shell$

这种方法的思想是先找出指定id的配置所在的区域,即从哪行开始,到哪行结束。只要找到这个区间就好办了,因为sed可以指定只处理的区间。获取区间的方法解释如下:

cat -n $configPath #给每一行加上行号
| grep "\[id=.*\]" #打印所有的`id`配置行
| grep -A 1 "\[id=$userID\]" #打印匹配的ID行,及下一行,下一行即为下一个配置section的起始行
| awk '{print $1}' | xargs #提取两个行号,即所需section的起始行和下一个配置section的起始行。

这种方法当时也是突发其想,想出来的。现在回头看看,其实使用倒推法应该不难想出这种方法。即最后应该是使用sed处理指定区间的文本。那前提就是需要找出section的区间了。而区间也就是两个行号,自然想到要cat -n了。

免责声明:文章转载自《shell 读配置文件》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Hisi 使用GDB调试(图形界面调试)index+small+row+if经典函数组合应用下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

教会你Linux Shell自动交互的三种方法

你了解Linux系统么?你是Linux系统的应用者么?如果你要学习linux,你可能会遇到Linux Shell自动交互问题,这里将介绍Linux Shell自动交互的解决方法,在这里拿出来和大家分享一下。 一、背景 shell脚本在处理自动循环或大的任务方面可节省大量的时间,通过创建一个处理任务的命令清单,使用变量、条件、算术和循环等方法快速创建脚本以完...

[zz]Linux中的/etc/profile文件

【一、让/etc/profile文件修改后立即生效】 方法1:让/etc/profile文件修改后立即生效 ,可以使用如下命令:# .  /etc/profile注意: . 和 /etc/profile 有空格方法2:让/etc/profile文件修改后立即生效 ,可以使用如下命令:# source /etc/profile附:Linux中source命令...

《Linux命令行与shell脚本编程大全》第二十五章 创建与数据库、web及电子邮件相关的脚本

25.1 MySQL数据库 /* 但是我在虚拟机上安装的时候居然不提示输入密码。 这个可以参考http://blog.csdn.net/sinat_21302587/article/details/76870457 导致登录的时候不知道账号密码。 默认的账号密码在 /etc/mysql/debian.cnf上。如下图,user和password就是账号密码...

解决Jenkins用shell脚本部署后,Jenkins自动杀掉启衍生出来的守护进程

Jenkins部署java项目遇到的问题: 1、Jenkins执行构建后,需要手动执行startup.sh,站点才能正常访问 产生原因: shell脚本发布时,会衍生进程,Jenkins默认会自动杀掉衍生进程 解决方案: 在执行shell脚本前,加个build_ID参数即可 BUILD_ID=DONTKILLME...

解决 'adb root' 时提示 'adbd cannot run as root in production builds'

测试手机是红米3s,刷了原生第三方rom,安卓9.0 在刷了magisk获取root权限后,adb调试无法获取root权限。 注意: 1.在手机上,装上安卓终端软件,直接在本地系统上root是可以的 2.远程调试,不管是有线adb还是wifi adb,都无法通过adb root提权,但是可以在进入shell后再通过su切换到root 谷歌了下,发现是安卓9...

shell脚本中if的“-e,-d,-f”

文件表达式-e filename 如果 filename存在,则为真-d filename 如果 filename为目录,则为真-f filename 如果 filename为常规文件,则为真-L filename 如果 filename为符号链接,则为真-r filename 如果 filename可读,则为真-w filename 如果 filenam...