这个脚本是放到应用程序里去使用的,所以main函数里主要是三个功能:(1)杀死正在运行的应用进程(2)把新的应用程序覆盖旧的(3)重启应用程序。但实现着三个功能需要一些函数去辅助,以下先讲讲其中一些函数,再把完整的代码给大家。
目录
进程是否存在函数
# 进程是否存在
# 参数:进程名字
# 返回值:RET_EP 1 存在,0不存在
ExistProcess ( )
{
#echo "ps -ef | grep $1 | grep -v grep"
CHECK=`ps -ef | grep $1 | grep -v grep` #列出所有的进程信息、再从列出项中找到包含进程名字的、grep -v 排除掉包含grep的
#因为本条指令就是包含进程名的,但我们要查找的是进程本身
if [ -z "$CHECK" ];then #检查变量$CHECK是否为空,-z测试字符串是否为空
RET_EP=0
else
RET_EP=1
fi
#echo $CHECK
}
大家可以先挨着输入一下这些命令,就知道每条命令具体再处理什么。可以用echo打印到出口去看看,我这里是注释掉了。
比较文件函数
我们升级应用程序一定会有一个比较的过程,如果不一样则升级,一样就无需升级。
# 两个文件是否相同
# 参数1:文件1路径
# 参数2:文件2路径
# 返回值:RET_IS_SAME_FILE,1 相同 0 不相同
IsSameFile ( )
{
LOG "==========in IsSameFile=========="
LOG "param1 is $1"
LOG "param2 is $2"
if [[ $# -lt 2 ]];then #检查传递给函数的参数数量是否少于2个,$# ——添加到Shell的参数个数 -lt比较运算符小于,小于2说明给的参数不够
RET_IS_SAME_FILE=0
fi
FILE_DATE1=`ls -e "$1" | cut -c30-69` #列出参数1路径下应用程序的信息,截取第30到69的字符(代码大小,最后修改日期时间)
FILE_DATE2=`ls -e "$2" | cut -c30-69` #列出参数2路径下应用程序的信息,截取第30到69的字符(代码大小,最后修改日期时间)
#DATE_DIFF=$((FILE_DATE1 - FILE_DATE2))
LOG "$FILE_DATE1"
LOG "$FILE_DATE2"
if [[ "$FILE_DATE1" == "$FILE_DATE2" ]];then #比较文件大小及最后修改时间,一样则返回1,不一样则返回0
RET_IS_SAME_FILE=1
else
RET_IS_SAME_FILE=0
fi
}
LOG是我们的一个日志函数,下面完整的代码里会有,我们这里是通过比较文件的修改时间,来判断需不需要升级的。
升级函数
其实升级,就是一个文件拷贝的过程。
# 更新文件
# 参数1 新文件路径
# 参数2 目标文件路径
# 返回值 RET_UPDATE: 0-更新失败 1-成功 2-无需更新
UpdateFile ( )
{
IsSameFile $1 $2 #调用比较程序函数,一样则不需要更新
#LOG "$1 $2 is same : $RET_IS_SAME_FILE"
if [[ $RET_IS_SAME_FILE == 1 ]];then
LOG "$1 文件一致,无需更新!"
RET_UPDATE=2
else #不一样则将参数一路径下的文件拷贝到参数二路径下文件
cp -p "$1" "$2"
if [[ $? == 0 ]];then #用来检查上一个命令执行的退出状态码是否为0
LOG "更新文件, 成功: $2"
RET_UPDATE=1
else
LOG "更新文件, 失败: $2"
RET_UPDATE=0
fi
fi
}
杀死进程函数
# 杀死进程
# 参数 进程名字
KillProcess () {
echo $1
Linux_new_id=`ps -ef | grep $1 | grep -v grep | awk '{print $1}'`
echo $Linux_new_id
for id in $Linux_new_id
do
kill $id
echo "killed $id"
done
}
在我们升级前需要先kill掉进程,所以这个函数就是实现,先找的这个进程本身,并将它杀死。
完整代码
完整代码里还包含了判断升级状态,和创建文件目录,打印日志到指定路径的小功能,更加完善。大家可以参考。大家如果测试时对路径做相应的修改就可以了。加入我们运行这hello1程序,在U盘里放入hello2,然后插入即可看到实现的效果。
#!/usr/bin/env bash
HARDDISK1_PATH='/opt' #放应用程序和回滚版本应用程序(其实总共就是这两个目录)
HARDDISK12_PATH='/HardDisk12' #放日志记录
# DRU_200C主控程序目录
PROGRAM_PATH='/opt' #就是第一个目录,只不过给个定义
LOG_PATH='/HardDisk12/USB_log' #日志的具体目录
PROGRAM_NAME='hello' #程序名称
# 升级结果缓存
# 0 : 升级失败
# 1 : 升级成功
# 2 : 无需升级
TEMP_RET_UPDATE_DRU_200C_ZK=2 #初始升级状态为无需升级
# 功能:DRU_200C主控升级状态处理
# 输入参数:升级状态
# 注:
# 若升级成功,且当前总的升级状态不是“升级失败”,则更新为“升级成功”;
# 若升级失败,则更新总的升级状态为“升级失败”
# 否则,不处理
DRU_200CUpdateStatusHandler ()
{
if [[ $1 == 1 ]];then # 若升级成功,且当前总的升级状态不是“升级失败”,则更新为“升级成功”;
if [[ $TEMP_RET_UPDATE_DRU_200C_ZK != 0 ]];then
TEMP_RET_UPDATE_DRU_200C_ZK=1
fi
elif [[ $1 == 0 ]];then # 若升级失败,则更新总的升级状态为“升级失败”
TEMP_RET_UPDATE_DRU_200C_ZK=0
fi
}
# 如果没有这两个目录就创建 HardDisk1 and HardDisk12
if [[ ! -d "$HARDDISK1_PATH" ]];then
mkdir "$HARDDISK1_PATH"
fi
if [[ ! -d "$HARDDISK12_PATH" ]];then
mkdir "$HARDDISK12_PATH"
fi
# 如果没有就创建 myapp-log directory
if [[ ! -d "$LOG_PATH" ]];then
mkdir "$LOG_PATH"
fi
#log函数,记录日志,保存在LOG_PATH='/HardDisk12/log_sys'里
LOG ( )
{
LOG_DATE=`date '+%Y-%m-%d'` #以日期命名log名称
echo `date '+%Y-%m-%d %H:%M:%S'` $1 >> "$LOG_PATH/$LOG_DATE.txt" #打印日期时间到日志里
echo `date '+%Y-%m-%d %H:%M:%S'` $1 #打印日期时间到终端
}
##########################################添加myapp版本号#################################################
LOG "myapp version: V2.0.0 20211102"
##########################################################################################################
# 进程是否存在
# 参数:进程名字
# 返回值:RET_EP 1 存在,0不存在
ExistProcess ( )
{
#echo "ps -ef | grep $1 | grep -v grep"
CHECK=`ps -ef | grep $1 | grep -v grep` #列出所有的进程信息、再从列出项中找到包含进程名字的、grep -v 排除掉包含grep的
#因为本条指令就是包含进程名的,但我们要查找的是进程本身
if [ -z "$CHECK" ];then #检查变量$CHECK是否为空,-z测试字符串是否为空
RET_EP=0
else
RET_EP=1
fi
#echo $CHECK
}
# 两个文件是否相同
# 参数1:文件1路径
# 参数2:文件2路径
# 返回值:RET_IS_SAME_FILE,1 相同 0 不相同
IsSameFile ( )
{
LOG "==========in IsSameFile=========="
LOG "param1 is $1"
LOG "param2 is $2"
if [[ $# -lt 2 ]];then #检查传递给函数的参数数量是否少于2个,$# ——添加到Shell的参数个数 -lt比较运算符小于,小于2说明给的参数不够
RET_IS_SAME_FILE=0
fi
FILE_DATE1=`ls -e "$1" | cut -c30-69` #列出参数1路径下应用程序的信息,截取第30到69的字符(代码大小,最后修改日期时间)
FILE_DATE2=`ls -e "$2" | cut -c30-69` #列出参数2路径下应用程序的信息,截取第30到69的字符(代码大小,最后修改日期时间)
#DATE_DIFF=$((FILE_DATE1 - FILE_DATE2))
LOG "$FILE_DATE1"
LOG "$FILE_DATE2"
if [[ "$FILE_DATE1" == "$FILE_DATE2" ]];then #比较文件大小及最后修改时间,一样则返回1,不一样则返回0
RET_IS_SAME_FILE=1
else
RET_IS_SAME_FILE=0
fi
}
# 更新文件
# 参数1 新文件路径
# 参数2 目标文件路径
# 返回值 RET_UPDATE: 0-更新失败 1-成功 2-无需更新
UpdateFile ( )
{
IsSameFile $1 $2 #调用比较程序函数,一样则不需要更新
#LOG "$1 $2 is same : $RET_IS_SAME_FILE"
if [[ $RET_IS_SAME_FILE == 1 ]];then
LOG "$1 文件一致,无需更新!"
RET_UPDATE=2
else #不一样则将参数一路径下的文件拷贝到参数二路径下文件
cp -p "$1" "$2"
if [[ $? == 0 ]];then #用来检查上一个命令执行的退出状态码是否为0
LOG "更新文件, 成功: $2"
RET_UPDATE=1
else
LOG "更新文件, 失败: $2"
RET_UPDATE=0
fi
fi
}
# 杀死进程
# 参数 进程名字
KillProcess () {
echo $1
Linux_new_id=`ps -ef | grep $1 | grep -v grep | awk '{print $1}'`
echo $Linux_new_id
for id in $Linux_new_id
do
kill $id
echo "killed $id"
done
}
main(){
GREPRET=`grep 'sd[a-z][0-9]\? /media' /proc/mounts` #在/proc/mounts文件中查找挂载在/media目录下的块设备(通常代表U盘或硬盘分区),
#sd[a-z][0-9]\?匹配如sda1、sdb等常见的块设备名称。
UDISK_PATH=$(echo $GREPRET | { read UP1 UP2 UP3; echo $UP2; })
echo $UDISK_PATH
if [[ -e "$UDISK_PATH/$PROGRAM_NAME" ]];then
IsSameFile "$UDISK_PATH/$PROGRAM_NAME" "$PROGRAM_PATH/$PROGRAM_NAME"
if [ $RET_IS_SAME_FILE == 1 ];then
LOG "DRU_200C_ZK Program need not update"
exit 1
else
LOG "Check if the DRU_200C_ZK process exists?"
ExistProcess "$PROGRAM_NAME"
if [ $RET_EP == 1 ];then
LOG "Check ok, quit DRU_200C_ZK program"
KillProcess $PROGRAM_NAME
fi
UpdateFile "$UDISK_PATH/$PROGRAM_NAME" "$PROGRAM_PATH/$PROGRAM_NAME"
DRU_200CUpdateStatusHandler $RET_UPDATE
if [[ $TEMP_RET_UPDATE_DRU_200C_ZK == 1 ]];then
LOG "Update DRU_200C_ZK Program, success"
echo -e -n "\x00" > "$FILE_DOWNLOADS_VERSION"
cd "$PROGRAM_PATH"
"./$PROGRAM_NAME" & #非阻塞运行应用程序
sleep 10s
exit 1
elif [[ $TEMP_RET_UPDATE_DRU_200C_ZK == 2 ]];then
LOG "DRU_200C_ZK Program need not update" #前面存在IsSameFile判断,实际上不存在该分支,只作为逻辑出口
else
LOG "Update DRU_200C_ZK Program, fail: copy fail"
exit 0
fi
fi
else
LOG "DRU_200C_ZK upgrade program does not exist"
exit 1
fi
# sleep 10s
}
main
实现效果
刚开始它会检测到版本不一样实现升级,当升级完后再次重启发现U盘里和运行的是一个版本后则无需升级了。