Shell脚本在现代软件开发中扮演着重要角色,特别是在配置管理方面。本文将讨论如何通过优化Shell脚本,提升配置管理的效率和质量,使其更具可读性、可维护性和实用性。
一、基本文件展示
首先,我们来看看当前的配置文件内容和部分相关数据:
(一)confd-general-config.conf文件展示
以下是应用程序的配置文件,包含了各项重要的服务和连接信息:
# cat confd-general-config.conf
# ETCD服务器的主机IP和端口配置
ETCD_SERVER_HOSTIP=192.168.3.103
ETCD_SERVER_PORT=2379
# 内部网络段设置,用于内部通信和地址分配
innernetworksegement=192.168.3
# PostgreSQL数据库主从连接地址
pgconn=10.47.245.110:13306,10.47.245.110:23306
# Kafka消息队列的连接地址,包括多个Broker节点
kafkaconn=10.47.223.223:9090,10.47.223.223:9091,10.47.223.223:9092
# Zookeeper的连接地址,用于协调Kafka集群
zkconn=10.47.223.223:2181,10.47.223.223:2182,10.47.223.223:2183
# Redis缓存服务器的连接地址,多节点部署
redisconn=10.47.223.223:8000,10.47.223.223:8001,10.47.223.223:8002
# Kubernetes API服务器的URL地址
k8sapiserverurl=10.47.225.97:8080
# Kubernetes使用的NFS主机地址
k8snfshost=10.47.225.92
# 联创服务的URL地址,用于特定服务调用
lianchuang_url=61.160.190.227:8298
(二)相关数据展示
# Kafka stream
spring.cloud.stream.kafka.binder.zk-nodes=10.47.223.223:2181,10.47.223.223:2182,10.47.223.223:2183
spring.cloud.stream.kafka.binder.brokers=10.47.223.223:9090,10.47.223.223:9091,10.47.223.223:9092
spring.cloud.stream.kafka.binder.configuration.security.protocol=SASL_PLAINTEXT
spring.cloud.stream.kafka.binder.configuration.sasl.mechanism=PLAIN
二、相关修改变更值代码展示
(一)思路总结
主要思路是从配置文件中获取特定键的值,并将这些值应用于应用程序的配置文件中。
getConfigValue函数
- 函数接受两个参数:文件名和键名,从配置文件中提取相应键的值。
- 使用grep和awk命令来解析配置文件,提取键值对,并去除额外的空格。
writeConfigValue函数
- 定义多个变量来存储从配置文件中获取的不同连接和地址信息。
- 如果应用程序的配置文件(如application.properties)存在,则根据获取的值更新配置文件。
- 对于IP段、ZooKeeper、Kafka和联创URL等关键信息,使用sed命令将其写入应用程序配置文件中。
- 如果存在bootstrap.properties文件,则根据需要更新eureka客户端的服务URL。
(二)脚本代码实现
function getConfigValue
{
[ $# -ne 2 ] && echo "function getConfigValue arguments error"
local fileName=$1
local key=$2
echo `cat ${fileName}| grep "${key}"| grep "=" | awk -F= '{print $2}' | tr -d " "`
}
function writeConfigValue()
{
K8SCONFIGDIR=/home/zyf/confdconfig
K8SCONFIGFILE=${K8SCONFIGDIR}/confd-general-config.conf
DBMASTURL=`getConfigValue ${K8SCONFIGFILE} pgconn | awk -F ',' '{print $1}'`
DBSLAVEURL=`getConfigValue ${K8SCONFIGFILE} pgconn | awk -F ',' '{print $2}'`
REDISURL=`getConfigValue ${K8SCONFIGFILE} redisconn`
KAFKAURL=`getConfigValue ${K8SCONFIGFILE} kafkaconn`
ZOOKEEPURL=`getConfigValue ${K8SCONFIGFILE} zkconn`
IPSEGEMENT=`getConfigValue ${K8SCONFIGFILE} innernetworksegement`
LIANCHUANGURL=`getConfigValue ${K8SCONFIGFILE} lianchuang_url`
if [ -f ${CONFIGDIR}/application.properties ]
then
if [ -n ${IPSEGEMENT} ]
then
sed -i -e "/^genid/s/\/[0-9]\{1,3\}.[0-9]\{1,3\}.[0-9]./\/${IPSEGEMENT}./g" ${CONFIGDIR}/application.properties
fi
if [ -n ${ZOOKEEPURL} ]
then
sed -i -e "/^spring.cloud.stream.kafka.binder.zk-nodes/s/spring.cloud.stream.kafka.binder.zk-nodes=.*/spring.cloud.stream.kafka.binder.zk-nodes=${ZOOKEEPURL}/" ${CONFIGDIR}/application.properties
fi
if [ -n ${KAFKAURL} ]
then
sed -i -e "/^kafka.binder.brokers/s/kafka.binder.brokers=.*/kafka.binder.brokers=${KAFKAURL}/" ${CONFIGDIR}/application.properties
sed -i -e "/^spring.cloud.stream.kafka.binder.brokers/s/spring.cloud.stream.kafka.binder.brokers=.*/spring.cloud.stream.kafka.binder.brokers=${KAFKAURL}/" ${CONFIGDIR}/application.properties
fi
if [ -n ${LIANCHUANGURL} ]
then
BRFOREVALUE=`getConfigValue ${CONFIGDIR}/application.properties lianchuang.url`
BRFORE=${BRFOREVALUE#*//}
sed -i "s/${BRFORE}/${LIANCHUANGURL}/g" ${CONFIGDIR}/application.properties
fi
fi
if [ -f ${CONFIGDIR}/bootstrap.properties ]
then
if [ -n ${IPSEGEMENT} ]
then
sed -i -e "/^eureka.client.serviceUrl.defaultZone/s/\/[0-9]\{1,3\}.[0-9]\{1,3\}.[0-9]./\/${IPSEGEMENT}./g" ${CONFIGDIR}/bootstrap.properties
fi
fi
}
(三)潜在的缺点分析
-
安全性问题:getConfigValue函数没有对文件路径或键名进行有效性验证,可能会导致安全漏洞,如路径注入或命令注入攻击。
-
错误处理不足:getConfigValue和writeConfigValue函数中没有充分的错误处理机制,如文件不存在或键名未找到时可能会导致意外终止或未定义行为。
-
可读性和维护性:使用反引号和多个sed命令可能会使代码难以阅读和维护。建议使用更现代的Shell语法 $(...) 代替反引号。
-
依赖于外部文件路径:函数中使用的配置文件路径(如CONFIGDIR变量)是外部硬编码的,不利于代码的移植和部署。
-
缺乏注释和文档:缺乏足够的注释和文档,不利于他人理解和维护代码。
三、优化与扩展
我们可以对这个脚本进行优化,以提高其可读性、灵活性和稳健性。
(一)优化思路分析
- 增加注释:为每个函数和重要代码段添加注释,以提高可读性和可维护性。
- 参数验证:加强参数验证和错误处理,确保脚本的稳健性。
- 使用函数:将重复代码提取到函数中,以提高代码的复用性。
- 配置文件路径:将配置文件路径和其他常量定义在脚本的开头,方便管理和修改。
- 日志记录:添加日志记录功能,便于调试和监控。
- 命令行参数:允许通过命令行参数传递一些常用参数,以增加灵活性。
- 避免使用反引号:使用
$(...)
代替反引号...
,因为前者更具可读性。
(二)脚步验证
#!/bin/bash
# Constants
K8SCONFIGDIR=/home/zyf/confdconfig
K8SCONFIGFILE=${K8SCONFIGDIR}/confd-general-config.conf
CONFIGDIR=/path/to/config # 修改为实际路径
# Function to get configuration value
getConfigValue() {
if [ $# -ne 2 ]; then
echo "function getConfigValue arguments error"
return 1
fi
local fileName=$1
local key=$2
grep -E "^${key}=" "${fileName}" | awk -F= '{print $2}' | tr -d " "
}
# Function to write configuration values
writeConfigValue() {
# Fetch values from the configuration file
DBMASTURL=$(getConfigValue "${K8SCONFIGFILE}" pgconn | awk -F ',' '{print $1}')
DBSLAVEURL=$(getConfigValue "${K8SCONFIGFILE}" pgconn | awk -F ',' '{print $2}')
REDISURL=$(getConfigValue "${K8SCONFIGFILE}" redisconn)
KAFKAURL=$(getConfigValue "${K8SCONFIGFILE}" kafkaconn)
ZOOKEEPURL=$(getConfigValue "${K8SCONFIGFILE}" zkconn)
IPSEGEMENT=$(getConfigValue "${K8SCONFIGFILE}" innernetworksegement)
LIANCHUANGURL=$(getConfigValue "${K8SCONFIGFILE}" lianchuang_url)
# Update application.properties
if [ -f "${CONFIGDIR}/application.properties" ]; then
[ -n "${IPSEGEMENT}" ] && sed -i -e "/^genid/s/\/[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\./\/${IPSEGEMENT}./g" "${CONFIGDIR}/application.properties"
[ -n "${ZOOKEEPURL}" ] && sed -i -e "/^spring.cloud.stream.kafka.binder.zk-nodes/s/.*/spring.cloud.stream.kafka.binder.zk-nodes=${ZOOKEEPURL}/" "${CONFIGDIR}/application.properties"
[ -n "${KAFKAURL}" ] && sed -i -e "/^kafka.binder.brokers/s/.*/kafka.binder.brokers=${KAFKAURL}/" "${CONFIGDIR}/application.properties"
[ -n "${KAFKAURL}" ] && sed -i -e "/^spring.cloud.stream.kafka.binder.brokers/s/.*/spring.cloud.stream.kafka.binder.brokers=${KAFKAURL}/" "${CONFIGDIR}/application.properties"
if [ -n "${LIANCHUANGURL}" ]; then
BRFOREVALUE=$(getConfigValue "${CONFIGDIR}/application.properties" lianchuang.url)
BRFORE=${BRFOREVALUE#*//}
sed -i "s/${BRFORE}/${LIANCHUANGURL}/g" "${CONFIGDIR}/application.properties"
fi
fi
# Update bootstrap.properties
if [ -f "${CONFIGDIR}/bootstrap.properties" ]; then
[ -n "${IPSEGEMENT}" ] && sed -i -e "/^eureka.client.serviceUrl.defaultZone/s/\/[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\./\/${IPSEGEMENT}./g" "${CONFIGDIR}/bootstrap.properties"
fi
}
# Main script execution
writeConfigValue
四、总结
我们详细展示了现有的配置文件内容和相关代码,并针对原始脚本提出了优化建议。优化后的脚本不仅提高了代码的可读性、灵活性和稳健性,还增加了实用性和可维护性。具体的优化措施包括增加注释、加强参数验证、提取重复代码到函数中、定义常量、添加日志记录功能、支持命令行参数传递以及使用更具可读性的语法结构。希望对以后的编码有所帮助。