![请添加图片描述](https://i-blog.csdnimg.cn/direct/97a7ea1052984d75938fdafaefb729e9.png)
前言
- 上一篇文章我们提到了使用
yaml-cpp
编写了实时检测参数文件config.yaml的文件系统时间自动进行无编译实时动态同步运行程序的参数,本文将使用bash
脚本为用户提供一个修改参数的脚本接口,效果如下。 ![请添加图片描述](https://i-blog.csdnimg.cn/direct/b48c062da81c43688c089e3352380a5d.png)
- 基于yaml-cpp的C++参数服务器设计
![请添加图片描述](https://i-blog.csdnimg.cn/direct/823626cac3344c6dab4fc13c2d67b880.png)
代码分析
- 老规矩先上全部代码,然后我们结合本代码对
bash
语法进行分析
#!/bin/bash
CONFIG_FILE="/home/lzh/params_server/src/params_server/src/config.yaml"
print_config_key_by_index() {
local index=$1
local key="${config_keys[$index]}"
if [[ -n $key ]]; then
echo "参数名称: $key"
else
echo "无效的序号。"
fi
}
print_config() {
local i=0
echo "==========================================================="
while IFS=':' read -r key value
do
value=$(echo$value | xargs)
echo "$i:$key=$value"
config_keys[$i]=$key
config_values[$i]=$value
((i++))
done < <(grep -v '^#' "$CONFIG_FILE" | grep .)
echo "==========================================================="
}
modify_config() {
local index=$1
local new_value=$2
local key="${config_keys[$index]}"
if [[ -n $key ]]; then
sed -i "/^$key: /c\\$key: $new_value" "$CONFIG_FILE"
echo "参数 '$key' 已更新为 '$new_value'。"
else
echo "无效的序号。"
return 1
fi
}
![请添加图片描述](https://i-blog.csdnimg.cn/direct/84c06b95b044470282dd8d582efde4d9.png)
print_config
while true; do
echo "请输入要更改的参数序号(或输入 'q' 退出):"
if ! read -t 180 -r user_input; then
echo "超时,你到底改不改啊喂!!!。"
break
fi
if [[ $user_input == 'q' ]]; then
break
elif ! [[ $user_input =~ ^[0-9]+$ ]]; then
echo "无效输入。请输入一个数字或 'q' 退出。"
continue
elif [ $user_input -ge ${#config_keys[@]} ]; then
echo "无效序号。请输入一个有效的数字。"
continue
fi
print_config_key_by_index $user_input
echo "请输入新的值:"
if ! read -t 180 -r new_value; then
echo "超时,你到底改不改啊喂!!!"
break
fi
modify_config $user_input "$new_value"
print_config
done
print_config_key_by_index() {
local index=$1
local key="${config_keys[$index]}"
if [[ -n $key ]]; then
echo "参数名称: $key"
else
echo "无效的序号。"
fi
}
- 上述是一个辅助的打印函数,依次声明了
index
和key
两个函数内的局部变量,$1
代表函数调用时传入的第一个参数,而${config_keys[$index]}
是使用索引$index
来访问config_keys数组
中的元素。 - 在
bash
脚本中,$
符号通常用于引用变量。
-n
参数用于判断字符串是否非空,上述配合打印函数判断传入索引对应的参数是否存在
print_config() {
local i=0
echo "==========================================================="
while IFS=':' read -r key value
do
value=$(echo$value | xargs)
echo "$i:$key=$value"
config_keys[$i]=$key
config_values[$i]=$value
((i++))
done < <(grep -v '^#' "$CONFIG_FILE" | grep .)
echo "==========================================================="
}
- 上述代码读取config.yaml并向用户展示所有的参数并自动对参数进行排序
- 在
bash
中,while循环一般长这样:while CONDITION
do
done
IFS=':'
用于设置分隔符(Internal Field Separator, IFS)为冒号:,这样read命令会将每行按冒号分割成两部分。read -r key value
读取每行中的两部分,分别赋值给变量key
和value
。也就是参数名字和参数值value=$(echo$value | xargs)
这一行代码很有意思
echo$value
这里在输出变量value的值|
:这是管道操作符,它将echo$value
命令的输出作为下一个命令xargs
的输入。xargs
:这里被用来去除输入的前后空格。当xargs
没有接收到其他命令参数时,它会简单地读取其标准输入,去除任何前导和尾随的空白字符,并输出结果。
((i++))
:是一个算术扩展(Arithmetic Expansion)的语法,确保bash
能顺利执行自增< <(grep -v '^#' "$CONFIG_FILE" | grep .)
< <( ... )
:这是进程替换(Process Substitution)的语法。这里放在while循环后面是将这行指令的输出作为while循环的输入重定向部分。(类似于输入重定向)grep -v '^#' "$CONFIG_FILE"
,grep
过滤匹配以井号(#)开头的注释grep .
进一步过滤掉那些完全由空白字符组成的行。
- 这样通过
grep
对参数文件进行注释和空行的过滤后通过进程替换
,把整个有效参数文件的输出作为while循环的读取并存储参数名字和参数值,就可以有效向用户呈现参数表后后续的修改逻辑了
modify_config() {
local index=$1
local new_value=$2
local key="${config_keys[$index]}"
if [[ -n $key ]]; then
sed -i "/^$key: /c\\$key: $new_value" "$CONFIG_FILE"
echo "参数 '$key' 已更新为 '$new_value'。"
else
echo "无效的序号。"
return 1
fi
}
sed -i "/^$key: /c\\$key: $new_value" "$CONFIG_FILE"
这里说说sed
-i
选项表示直接在文件上进行修改,而不是输出到标准输出。/^$key: /
这是一个正则表达式,用于匹配配置文件中的特定行。c
:这是sed
命令的替换操作符,用于在找到匹配的行时进行替换。\\$key:$new_value
替换为新的参数,前面有一个反斜杠\,以防止sed将其作为特殊字符处理。
while true; do
echo "请输入要更改的参数序号(或输入 'q' 退出):"
if ! read -t 180 -r user_input; then
echo "超时,你到底改不改啊喂!!!。"
break
fi
if [[ $user_input == 'q' ]]; then
break
elif ! [[ $user_input =~ ^[0-9]+$ ]]; then
echo "无效输入。请输入一个数字或 'q' 退出。"
continue
elif [ $user_input -ge ${#config_keys[@]} ]; then
echo "无效序号。请输入一个有效的数字。"
continue
fi
print_config_key_by_index $user_input
echo "请输入新的值:"
if ! read -t 180 -r new_value; then
echo "超时,你到底改不改啊喂!!!"
break
fi
modify_config $user_input "$new_value"
print_config
done
- 最后的主函数,写了一个死循环
read -t 180
它检查用户输入是否在180秒内完成。指定超时参数elif ! [[ $user_input =~ ^[0-9]+$ ]]
检测用户是否输入是数字[ $user_input -ge ${#config_keys[@]} ]
-ge
:这是大于等于(greater than or equal to)的比较运算符。- 使用
${#array[@]}
这种形式可以获取数组的长度 - 上述用于判断用户输入的序号是否超出参数列表的长度—>是否为无效参数
总结
- 上述只是使用
bash
简单实现的一个用户使用参数服务器的bash脚本接口,如有错误,欢迎指正~