一次编写Shell脚本的过程
Posted DevinTest测试开发实践
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一次编写Shell脚本的过程相关的知识,希望对你有一定的参考价值。
本文记录一次简单的编写Shell脚本的过程, 希望对新手略有启发帮助.
设计
使用工具: PlantUML
与其他语言一样, 在编写一个可执行程序/脚本前, 逻辑设计必不可少. 通常我的做法是, 在纸上简单用圈与线构思想法, 再用PlantUML画出具体的流程图.
UML脚本
以下是完整的uml脚本, 涉及到的几个关键词为: if else 判断, repeat 循环, fork 同级操作.
建议访问官网 http://plantuml.com/ , 下载pdf版学习更多PlantUML用法!
@startuml
start
if (docker-compose installed?) then (yes)
repeat
:print selection;
fork
:init mongo;
:docker compose -f
init_mongo.yml up;
forkagain
:build web;
:print now ip;
if (need change ip?) then (yes)
:enter ip;
endif
:change config.js;
if (start build?) then (yes)
:docker compose -f
build_web.yml up;
else (no)
stop
endif
forkagain
:run xtest;
endfork
repeat while(exit?) is (no)
end
else (no)
:print "Install first!";
stop
endif
@enduml
流程图
生成的流程图如下:
编写Shell脚本
遇到的几个问题:
Q1: 如何判断当前环境是否装有某个工具?
A1: 以 docker-compose
为例, 将执行 which docker-compose
的结果返回给一个变量, 判断该变量为空则docker-compose未安装, 不为空则已安装. (具体参考函数 checkEnv
)
Q2: 如何编写函数?
A2: 参考菜鸟教程: http://www.runoob.com/linux/linux-shell-func.html
除了编写函数, 处理参数的几个关键字也要了解, 其中用 $?
显示最后命令的退出状态, 在函数中可以用 return 1
表示执行失败, 用 return 0
表示执行成功, 然后在函数外使用 if
判断函数执行状态, 并作出相对应的操作.
Q3: 如何提取一个文件中的 IP ?
A3: 参考论坛5楼答案: http://bbs.chinaunix.net/thread-881629-1-1.html
该答案并非很严谨的实现对 IP 的提取, 实际过程中需要对数字的位数等做判断.
cat config.js |grep -o -P "(\d+\.)(\d+\.)(\d+\.)\d+"
具体请查看函数 getIP
Q4: 如何修改某个文件的第一行为想要的内容?
A4: 修改文件通常使用的 sed
命令.
参考博客: http://blog.sina.com.cn/s/blog_68402d7b0102w794.html
使用 sed '1c Hi' ab
可以将第一行代替为Hi, 可以将字符串Hi
替换为参数, 实现在读取到键盘输入后, 赋值给该参数, 再将文件第一行替换为该参数.
Q5: 如何读取键盘输入?
A5: read a
即将键盘回车前的输入赋值给 a
变量
Q6: 为何A4中的参数写入文件后为 $a
参数名, 而非a参数的值?
A6: 参考: https://www.jianshu.com/p/78522b72bdd8
在Shell中, 双引号与单引号有个重要的区别就是, 对变量的引用只能在双引号中, 因此需要用
sed -i "1c $a" config.js
Q7: 如何编写选择功能?
A7: 使用 case
关键字完成.
Q8: 如何编写一个死循环?
A8: 参考: https://blog.csdn.net/askbai666888/article/details/8492348
while :
do
# do something
done
" :" (空格+冒号)表示实现一个空语句,什么也不做,相当于C语言的";"
完整的Shell脚本
#!/bin/bash
function checkEnv(){
res=`which docker-compose`
if [ "$res"x != ""x ]; then
return 0
else
return 1
fi
}
# 1: init mongo
function initMongo(){
echo "正在初始化MongoDB, 若失败或不小心退出请重试该步骤..."
sudo docker-compose -f init_mongo.yml up
echo "始化MongoDB完成!"
}
# 2: init node
function getIP(){
ip=`cat config.js |grep -o -P "(\d+\.)(\d+\.)(\d+\.)\d+"`
echo $ip
}
function setIP(){
echo "是否需要重置 IP ? [y/n]"
read ans
if [ "$ans"x = "y"x ] || [ "$ans"x = "Y"x ]; then
read ip
setConfigJS $ip
elif [ "$ans"x = "n"x ] || [ "$ans"x = "N"x ]; then
echo "未修改 IP"
return 0
else
echo "输入有误"
return 1
fi
}
function setConfigJS(){
echo "IP 已修改为: (此处 IP 显示正确才可编译!)"
a="var apiHost = 'http://$1:8009/';"
sed -i "1c $a" config.js
getIP
}
function buildWeb(){
echo "正在编译前端代码..."
sudo docker-compose -f build_web.yml build --no-cache
sudo docker-compose -f build_web.yml up
}
function start(){
echo "正在启动 x-utest 测试平台..."
echo "启动完成后, 浏览器输入 IP:8099 访问."
sudo docker-compose up
}
function main(){
clear
echo "输入对应数字选择你需要的操作:"
echo " 1.初始化 MongoDB 2.编译前端代码 3.启动 x-utest 0.退出"
echo "注意: 执行步骤 3 前, 请先完成步骤 1, 2"
read select1
case "$select1" in
1)
initMongo
;;
2)
echo "当前 IP 为: (此处 IP 显示正确才可编译!)"
getIP
setIP
if [ $? = 0 ]; then
echo "是否开始编译前端代码? [y/n]"
read ans2
if [ "$ans2"x = "y"x ] || [ "$ans2"x = "Y"x ]; then
buildWeb
elif [ "$ans2"x = "n"x ] || [ "$ans2"x = "N"x ]; then
echo "未编译, 正在返回主菜单..."
return 1
else
echo "输入有误, 正在返回主菜单..."
return 1
fi
else
return $?
fi
;;
3)
start
;;
*)
echo "exit"
exit 1
;;
esac
sleep 3;
}
checkEnv
if [ $? = 0 ]; then
while :
do
main
done
else
echo "请先安装 docker-compose!"
exit $?
fi
点击“阅读原文”,简书版查看更方便!
以上是关于一次编写Shell脚本的过程的主要内容,如果未能解决你的问题,请参考以下文章