脚本自动更新的实现

为了方便撰写博客,我设计了脚本diary.sh用来自动化处理使用hexo编辑博客文章并同时发布到gitlab上的。经过一段时间的测试,此脚本基本稳定,我可以很好的编写博客了。但是也有一个问题,就是如果我在这台机器上安装了diary, 但是我以后有可能对此脚本更新,但是每次更新后我都需要重新安装一下这个脚本,如果我换了电脑,但是之前编写的脚本又没有随身携带,同时如果有别人也使用我的脚本写博客,这将会带来维护此脚本的麻烦。于是我需要此脚本可以自动升级!

升级程序设计思路

  1. 使用gitlab官方api 和本地的curl命令,查询存放脚本diary.sh的仓库的commit时间,也就是推送时间。

  2. gitlab api返回的数据很多,我们只需要commit时间,于是需要借助awk来选择对应的时间。

  3. 在脚本中写入一个编辑的时间到变量ModifyTime中,脚本启动时先用命令curl请求gitlab api返回commit时间,即完成前两步,将此时间写 入变量GitlabTime中 然后比对两个时间,如果服务器上的时间更新,则脚本从服务器上下载diary.sh脚本,同时使用sed -i 将脚本中的时间 取代为服务器上的时间,这样只要服务器没有新的推送,则两个时间一致,不需要更新。如果在某台电脑上修改了脚本diary.sh并上传到了服务器 ,则下次启动脚本diary.sh时将自动更新到和服务器同步的版本。

代码分析

实现代码

1
2
3
4
5
6
7
8
9
10
11
ModifyTime="2022-11-13T13:57:22.000+08:00"
GitLabTime=$(curl -s --request GET "https://gitlab.com/api/v4/projects/41166909/repository/commits" |awk -F'["]' '{print $12}')
OldTime=`date -d "$ModifyTime" +%s`
NewTime=`date -d "$GitLabTime" +%s`
if [ $NewTime -gt $OldTime ]; then
echo "Diary is updating, please wait ......"
sudo curl -o $DIARYEXE https://gitlab.com/fengzhenhua/diary/-/raw/main/diary.sh\?inline\=false
sudo sed -i "s/^ModifyTime.*$/ModifyTime=\"${GitLabTime}\"/g" $0
echo "Update completed, please run diary again"
exit
fi

代码分析

  • 第1行: 定义脚本修改时的时间,这部分在安装程序后,会被服务器时间覆盖
  • 第2行: 获取服务器diary仓库的commit信息,通过管道传输给awk ,获取服务器时间
  • 第3行: 将修改时间通过date命令转换为时间戳
  • 第4行: 将服务器时间通过date命令转换为时间戳
  • 第5行: 通过比对时间戳,确定两个时间先后顺序,如果服务器上时间更新则执行更新命令
  • 第6行: 发出自动更新通知
  • 第7行: 使用curl命令从服务器下载diary.sh脚本到标准脚本安装路径$DIARYEXE
  • 第8行: 将此次升级后的服务器时间写入脚本的修改时间位置,取代原来的修改时间
  • 第9行: 发出更新完毕通知
  • 第10行: 退出程序

参考事项

  1. 关于仓库帐号认证,对于公共的仓库(也就是public),不需要认证,而对于个人的仓库,就需要认证,认证方式有好多种。而我目前仅测试了一种token,这个token,可以通过右上角头像-> Edit profile 然后右侧 Access Token 来设置,有效期可以自行设置。

  2. How to use the API 中的例子为

    1
    curl "https://gitlab.example.com/api/v4/projects"
    上述这个网址应该是部署时自己的网站名,而我们是部署到gitlab上的,所以直接删除example即可。变成
    1
    curl "https://gitlab.com/api/v4/projects"
    认证方式有两种书写方式:

  • private-token写在链接后面的形式
    1
    curl "https://gitlab.example.com/api/v4/projects?private_token=<your_access_token>"
  • private-token写在链接前面的形式
    1
    curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects"
    我个人感觉使用前置方法要好一些,这样在写命令时可以直接复制后修改后面的部分。如果脚本需要认证PRIVATE-TOKEN,则可以如下书写
    1
    curl -s --header "PRIVATE-TOKEN: <your_access_token>" --request GET "https://gitlab.com/api/v4/projects/:project_id/repository/commits" |awk -F'["]'  '{print $12}' 
    上述命令中-s表示静默输出,不输出具体信息,同时请求命令--request GET应当放在TOKEN之后才行。
  1. 关于gitlab api的使用,请参考gitlab的官方文档:GitLab API Docs 这里我需说明一下说明文档中的语法表述问题,比如:List repository commits 中的一段代码

    1
    GET /projects/:id/repository/commits
    上述含义是将:id换成你自己项目的id号即可,这个可以在项目主面查询到,也可以使用api查询到,但是在这里对于首次使用的朋友还是通过网页在项目页查询易于操作。比如我的diary项目,id41166909,于是上述部分应当替换为
    1
    GET /projects/41166909/repository/commits

  2. 关于awk命令,请参考: Linux awk 命令

  3. 关于date命令,请参考: Linux date 命令

  4. 关于sed 命令,请参考: Linux sed 命令

关于一些命令的使用可以使用cmd --help 来查询使用手册,但是我推荐了网络上的文章,原因在于对于一些小白而言如果没有具体演示实例可能操作起来就会有问题,而一些网络上的文章可以给出具体使用实例,这一点大家结合具体问题的解决可以很快得到提高。一些命令也可以参考网站www.runoob.com