shell读取配置文件参数
# 简介
在shell脚本中读取配置文件使用 cat ,grep,awk和sed
# .env文件读取
# .env文件
# define env var default value.
# -------------开发环境-------------
# compose命令
COMPOSE_CMD=docker-compose
# -------------正式环境-------------
# compose命令
# COMPOSE_CMD=docker-compose
COMPOSE_CMD=config/docker/docker-compose
SAMY=SAMY11
SAMY2 = SAMY21111
2
3
4
5
6
7
8
9
10
11
# bash文件
#!/bin/bash
env_file=$(pwd)/env/master.env
function get_config(){
param=$1
# value=$(sed -E '/^#.*|^ *$/d' $env_file | awk -F "${param}=" "/${param}=/{print \$2}" | tail -n1)
value=$(sed -E '/^#.*|^ *$/d' $env_file | sed s/[[:space:]]//g | awk -F "${param}=" "/${param}=/{print \$2}" | tail -n1)
echo $value
}
compose_cmd=$(get_config COMPOSE_CMD)
echo $compose_cmd
SAMY=$(get_config SAMY)
echo $SAMY
SAMY2=$(get_config SAMY2)
echo $SAMY2
2
3
4
5
6
7
8
9
10
11
12
13
14
15
✗ sh env.sh
config/docker/docker-compose
SAMY11
SAMY21111
2
3
4
# 原理解析【要点】
- 读取配置文件时,将注释符#标记的行和空行全部过滤
sed -E '/^#.*|^ *$/d' $env_file
; - 使用sed s/[[:space:]]//g 去除 多余的空格符;
- 匹配指定参数相符的行并截取对应的值
awk -F "${param}=" "/${param}=/{print \$2}"
; - 获得的结果可能有多个,取最后一个值
tail -n1
; - 这4步都用
|
管道符连接,其作用是将当前的结果作为下一条命令的输入,连续处理以达到获取参数的最终目的;
# 全部替换 【要点】
my.cnf配置替换;
sed -i "s/\(skip-grant-tables\).*/#skip-grant-tables/" /etc/my.cnf
# env实践【要点】
default.env
# define env var default value.
# 一定默认生产线上环境
isPro = false
# 默认是中文版本
dafaultLang = en
# 只有英文版本
isOnlyEn = false
2
3
4
5
6
7
8
9
en.env
# 英文版本环境
# 只有英文版本
isOnlyEn = true
2
3
4
env.sh
脚本
###
# @Author: samy
# @email: yessz#foxmail.com
# @time: 2021-11-16 16:41:46
# @modAuthor: samy
# @modTime: 2021-11-18 19:03:25
# @desc:
# Copyright © 2015~2021 BDP FE
###
#!/bin/bash
defaultFile=$(pwd)/env/default.env
targetFile=$(pwd)/env/en.env
curDir=$(cd "$(dirname "$0")"; pwd)
webDir=${curDir}/web
function getEnvConf() {
param=$1
value1=$(sed -E '/^#.*|^ *$/d' $defaultFile | sed s/[[:space:]]//g | awk -F "${param}=" "/${param}=/{print \$2}" | tail -n1)
value2=$(sed -E '/^#.*|^ *$/d' $targetFile | sed s/[[:space:]]//g | awk -F "${param}=" "/${param}=/{print \$2}" | tail -n1)
if [ ! -n "$value2" ]; then
value=$value1
else
value=$value2
fi
echo $value
}
replacePro() {
varKey=$2
defaultValue=$3
varValue=$4
echo $varKey $varValue $defaultValue
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i "" "s#^var ${varKey} = ${defaultValue}.*#var ${varKey} = ${varValue};#g" $1
else
sed -i "s#^var ${varKey} = ${defaultValue}.*#var ${varKey} = ${varValue};#g" $1
fi
}
isPro=$(getEnvConf isPro)
dafaultLang=$(getEnvConf dafaultLang)
isOnlyEn=$(getEnvConf isOnlyEn)
replacePro ${webDir}/app/conf.js isPro false $isPro
replacePro ${webDir}/app/conf.js dafaultLang 'zh' $dafaultLang
replacePro ${webDir}/app/conf.js isOnlyEn false $isOnlyEn
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
优化后版本:替换匹配的一行;
function getEnvConf() {
param=$1
value1=$(sed -E '/^#.*|^ *$/d' $defaultFile | sed s/[[:space:]]//g | awk -F "${param}=" "/${param}=/{print \$2}" | tail -n1)
value2=$(sed -E '/^#.*|^ *$/d' $targetFile | sed s/[[:space:]]//g | awk -F "${param}=" "/${param}=/{print \$2}" | tail -n1)
if [ ! -n "$value2" ]; then
value=$value1
else
value=$value2
fi
echo $value
}
replacePro() {
varKey=$2
varValue=$3
echo $varKey $varValue
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i "" "s/\(${varKey} =\).*/\1 ${varValue};/" $1
else
sed -i "s#^var ${varKey} = ${defaultValue}.*#var ${varKey} = ${varValue};#g" $1
fi
}
isPro=$(getEnvConf isPro)
defaultLang=$(getEnvConf defaultLang)
isOnlyEn=$(getEnvConf isOnlyEn)
replacePro ${webDir}/app/conf.js isPro $isPro
replacePro ${webDir}/app/conf.js defaultLang $defaultLang
replacePro ${webDir}/app/conf.js isOnlyEn $isOnlyEn
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
优化添加判断文件是否存在规则;
#!/bin/bash
curDir=$(
cd "$(dirname "$0")"
pwd
)
webDir=${curDir}/web
#defaultFile=$(pwd)/env/.env.default # 得使用绝对路径,而不使用相对路径;
#targetFile=$(pwd)/env/.env.$1
defaultFile=${curDir}/env/.env.default
targetFile=${curDir}/env/.env.$1
function getEnvConf() {
param=$1
value1=$(sed -E '/^#.*|^ *$/d' $defaultFile | sed s/[[:space:]]//g | awk -F "${param}=" "/${param}=/{print \$2}" | tail -n1)
if [ -f $targetFile ]; then
value2=$(sed -E '/^#.*|^ *$/d' $targetFile | sed s/[[:space:]]//g | awk -F "${param}=" "/${param}=/{print \$2}" | tail -n1)
fi
if [ ! -n "$value2" ]; then
value=$value1
else
value=$value2
fi
echo $value
}
replacePro() {
varKey=$2
varValue=$3
echo $varKey $varValue
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i "" "s/\(${varKey} =\).*/\1 ${varValue};/" $1
else
sed -i "s/\(${varKey} =\).*/\1 ${varValue};/" $1
fi
}
if [ -n "$1" ]; then
if [ ! -f $targetFile ]; then
echo "File env not exist ${targetFile}"
echo "Please enter a legal ENV configuration!!!"
exit $E_NO_FILES
fi
fi
isPro=$(getEnvConf isPro)
defaultLang=$(getEnvConf defaultLang)
isOnlyEn=$(getEnvConf isOnlyEn)
replacePro ${webDir}/app/conf.js isPro $isPro
replacePro ${webDir}/app/conf.js defaultLang $defaultLang
replacePro ${webDir}/app/conf.js isOnlyEn $isOnlyEn
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
conf.js
//初始化默认项要跟上面的replacePro参数对应上;
var isPro = false;
var isOnlyEn = false;
var defaultLang = 'zh';
2
3
4
# .conf文件读取
大多数的配置文件都是以key=value
形式存在的。配置项完全由键值对组成。这样的配置文件读写也是最简单的,假如有以下配置文件user.conf
:
id=1
name=samy
phone=1234567890
2
3
# source
配置的读取很简单,只要将其source进来即可:
samy@samy-HP440:~/project/shell$ cat setup.sh
#!/bin/bash
source user.conf
echo "id = $id"
echo "name = $name"
echo "phone = $phone"
samy@samy-HP440:~/project/shell$ ./setup.sh
id = 1
name = samy
phone = 1234567890
samy@samy-HP440:~/project/shell$
2
3
4
5
6
7
8
9
10
11
12
13
# sed
上面的方法看似简单,但可能会有问题,shell的赋值语句=
号两边是不能有空格的,万一用户不小心多加了空白符呢。为防止这样的情况出现,还是换另一种写法比较安全:
samy@samy-HP440:~/project/shell$ cat user.conf
id=1
name=samy
phone=1234567890
samy@samy-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 samy
get_config user.conf name
samy@samy-HP440:~/project/shell$ ./setup.sh
samy
samy
samy@samy-HP440:~/project/shell$ cat user.conf
id=1
name=samy
phone=1234567890
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# section 配置文件读取
假如配置文件是由多个 section 组成的呢,就像下面这样:
[id=1]
name=samy
phone=1234567890
[id=2]
name=shaojiang
phone=5678901234
[id=3]
name=zhaotong
phone=8901234567
2
3
4
5
6
7
8
9
10
11
需要根据输入的id
来读写相应的配置项。这样就不能简单的使用前面介绍的方法了。遇到这种情况,可以使用下面这种方法,将配置文件拆分成多个,分别存放到不同的目录中:
config
-id1
-user.conf
-id2
-user.conf
-id3
-user.conf
2
3
4
5
6
7
根据id
读取不同目录下的配置文件即可。如果配置信息很多的话,推荐使用这种方法,目前在82平台上的机型配置就是使用这种方法来实现的。但若是配置信息很少,且可能有其他脚本也使用到了这个配置文件的时候,拆分配置文件可能就行不通了,需要寻找其他方法。要读写这种格式的配置文件比较复杂,下面是我使用的方法:
samy@samy-HP440:~/project/shell$ cat user.conf
[id=1]
name=samy
phone=1234567890
[id=2]
name=shaojiang
phone=5678901234
[id=3]
name=zhaotong
phone=8901234567
samy@samy-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 samy
get_config user.conf 2 name
samy@samy-HP440:~/project/shell$ ./setup.sh
shaojiang
samy
samy@samy-HP440:~/project/shell$
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
这种方法的思想是先找出指定id
的配置所在的区域,即从哪行开始,到哪行结束。只要找到这个区间就好办了,因为sed
可以指定只处理的区间。获取区间的方法解释如下:
cat -n $configPath #给每一行加上行号
| grep "\\[id=.*\\]" #打印所有的`id`配置行
| grep -A 1 "\\[id=$userID\\]" #打印匹配的ID行,及下一行,下一行即为下一个配置section的起始行
| awk '{print $1}' | xargs #提取两个行号,即所需section的起始行和下一个配置section的起始行。
2
3
4
这种方法当时也是突发其想,想出来的。现在回头看看,其实使用倒推法应该不难想出这种方法。即最后应该是使用sed
处理指定区间的文本。那前提就是需要找出section的区间了。而区间也就是两个行号,自然想到要cat -n
了。
# .ini文件读取
# 默认配置
比如在 eaxmple.ini
中
ftp_url = 127.0.0.1:223
ftp_user = admin
ftp_password = ftp~!@#$%
2
3
则在shell脚本中读取配置
FTP_URL = cat eaxmple.ini | grep ftp_url | awk -F'=' '{ print $2 }' | sed s/[[:space:]]//g
FTP_USER = cat eaxmple.ini | grep ftp_user | awk -F'=' '{ print $2 }' | sed s/[[:space:]]//g
FTP_PASSWORD = cat eaxmple.ini | grep ftp_password | awk -F'=' '{ print $2 }' | sed s/[[:space:]]//g
2
3
此处必须使用sed s/[[:space:]]//g 去除 多余的空格符; 之前没有使用sed 在自动登录ftp时,会出现总是连不上的问题。
另外附上 ftp下载文件代码 函数
l_user=$1
l_pass=$2
l_host=$3
l_file=$4
lftp << EOF
open ftp://$l_user:$l_pass@$l_host
get $l_file
EOF
2
3
4
5
6
7
8
注意:shell脚本和配置文件下载到本地之后可能会有格式问题,所以要首先执行格式命令去除 乱码影响 dos2unix filename
# 参考链接
- https://www.jianshu.com/p/b48e68c6f1a2
- https://www.cnblogs.com/kakaisgood/p/8330576.html
- https://blog.csdn.net/u013105439/article/details/52138007