0%

通过Shell脚本以FTP方式上传文件到虚拟主机实现Hexo博客自动发布

写这篇是因为最近将博客从服务器迁移到虚拟主机上了,我需要在Linux服务器上将我的Hexo博客编译后的静态页面上传至虚拟主机上,我的虚拟主机上传文件有且仅有一种方式:FTP

先说下我想实现的自动部署流程,我在Jenkins上做了监听,一旦我的Hexo代码仓库有新的提交,会触发任务脚本执行发布操作。具体要做的事都写在Shell脚本上,主要流程如下:

  1. 脚本配置,配置Hexo工作目录,静态文件上传目录,FTP配置信息等;
  2. 进入Hexo工作目录,更新代码,清除缓存,编译生成静态页面;
  3. 递归读取Hexo静态页面目录,创建文件夹/上传文件到FTP空间;
  4. 执行Hexo deploy命令,发布静态页面,我这里配置的是发布到Github;

流程大概就是这样,Shell脚本好说,FTP工具命令是踩了不少坑。说实话这FTP工具很不友好,一些常用的功能不支持,比如不能一次创建多级目录,只能一级一级逐层创建。

那为什么不用Hexo集成的FTPSync上传插件?我试过了,怎么都上传不成功,要么卡在MKDIRs complete.上,要么卡在Committing这里,日志如下:

1
2
3
4
5
6
7
8
9
10
11
12
# 初次发布,会先创建文件夹,文件夹创建成功后就卡主了不动了
...
- /htdocs/tags/随笔 created successfuly
- /htdocs/tags/隐式转换 created successfuly
MKDIRs complete.
# 到这里卡主不动,退出重新发布一次的话,前面文件夹已经创建了,这时候卡在提交文件这里了
...
Remove:[]
Consolidation complete.
Committing
-------------------------------------------------------------
# 再次卡在这里,FTP空间里目录创建成功了,文件一个没上传上去

FTPSync插件问题有待后续跟进,其实我做成现在这套流程也是有我自己的用处的,我可以在发布脚本中加入一些自定义操作,配合Jenkins能实现很多实用的功能。


部署流程有了,那么先安装FTP工具:

1
yum install ftp -y

关于LinuxFTP工具命令详解文末有附上,这里先贴上我的发布脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#!/bin/bash
# 博客工作目录
export BLOG_PATH=/develop/hexo
# 待上传的博客静态文件目录
export UPLOAD_PATH=/develop/hexo/public

# FTP空间访问地址
export FTP_HOST=guitu18.com
# FTP空间网站根路径
export FTP_ROOT_PATH=/htdocs
# FTP用户名
export FTP_USERNAME=guitu18.com
# FTP密码
export FTP_PASSWORD=guitu18.com

# 进入博客工作目录
cd $BLOG_PATH
echo -e "\033[44;37m>>> 博客文件更新 >>>\033[0m"
svn up
echo -e "\033[44;37m>>> 清除缓存文件 >>>\033[0m"
hexo cl
echo -e "\033[44;37m>>> 编译生成静态页面 >>>\033[0m"
hexo g

echo -e "\033[44;37m>>> 开始上传到FTP空间 >>>\033[0m"
# 递归读取目录
read_dir(){
# 遍历文件夹
for file in `ls -a $1`; do
# 当前文件完整路径
localFile=$1/$file
# 截取掉本地路径
len=${#UPLOAD_PATH}
# 截取当前文件所属目标文件夹
mdir=${1:$len}
# 如果file存在且是一个目录
if [ -d $localFile ]; then
# 排除.和..目录
if [[ $file != '.' && $file != '..' ]]; then
# 登录FTP,在FTP空间创建对应的文件夹
ftp -n <<EOF
open $FTP_HOST
user $FTP_USERNAME $FTP_PASSWORD
!echo '>>>mkdir: '$FTP_ROOT_PATH$mdir/$file
mkdir $FTP_ROOT_PATH$mdir/$file
close
bye
EOF
read_dir $localFile
fi
else
# 如果是文件,上传文件到FTP空间
ftp -n <<EOF
open $FTP_HOST
user $FTP_USERNAME $FTP_PASSWORD
cd $FTP_ROOT_PATH$mdir
lcd $1
binary
hash
prompt
!echo '>>> upload: '$localFile
put $file
close
bye
EOF
echo '>>> upload: '$localFile ' ===> 文件上传完成'
fi
done
}
# 执行
read_dir $UPLOAD_PATH

echo -e "\033[44;37m>>> 发布完成 >>>\033[0m"
echo -e "\033[44;37m>>> 推送至GitHub >>>\033[0m"
# 执行Hexo发布命令,发布到GitHub
hexo d
echo -e "\033[44;37m>>> 推送至GitHub完成 >>>\033[0m"

在脚本开头配置好相关参数就可以使用了,因为FTP是每次传输都需要握手,所以整个自动发布流程中最慢就是FTP上传了。

关于FTP工具的详细使用说明我找到了这篇博客:Linux文件传输FTP详解,每个命令说明讲的都比较详细了。

这里引用一些常用的命令及参数:

1
2
3
4
5
6
ftp(选项)(参数)
-d:详细显示指令执行过程,便于排错或分析程序执行的情况;
-i:关闭互动模式,不询问任何问题;
-g:关闭本地主机文件名称支持特殊字符的扩充特性;
-n:不使用自动登录;
-v:显示指令执行过程。

登录FTP实例后内部命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
ls: 显示服务器上的目录
get: 从服务器下载指定文件到客户端
put: 从客户端传送指定文件到服务器
open: 连接ftp服务器
quit: 断开连接并退出ftp服务器
cd directory: 改变服务器的当前目录为directory
lcd directory: 改变本地的当前目录为directory
bye: 退出ftp命令状态
ascii: 设置文件传输方式为ASCII模式
binary: 设置文件传输方式为二进制模式
!: 执行本地主机命令
cd: 切换远端ftp服务器上的目录
cdup: 上一层目录
close: 在不结束ftp进程的情况下,关闭与ftp服务器的连接
delete: 删除远端ftp服务器上的文件
get: 下载
hash: 显示#表示下载进度
mdelete: 删除文件,模糊匹配
mget: 下载文件,模糊匹配
mput: 上传文件,模糊匹配
mkdir: 在远端ftp服务器上,建立文件夹
newer: 下载时,检测是不是新文件
prompt: 关闭交互模式
put: 上传
pwd: 显示当前目录

各种各样的博客系统折腾多了,终究是要返璞归真,选择将工具和内容剥离的方式,回到最初始、最纯净的 Markdown 写作需求。

Hexo,你值得拥有。

明人不说暗话,如果你觉得可以的话,你懂的!