Liunx使用
进入文件后的操作
1. vi 打开文件后是命令模式状态,要用 i 或者 a 命令才可进入可编辑的状态哟。
2. 在编辑模式的情况下敲完内容,这个时候就应该保存文件了。
保存文件要按esc,这样就会退回vi 的命令模式。
3. 按完 esc 后输入冒号(英文的),然后就转换到了末行模式了,末行模式决定是否保存文件。
4. 末行模式下可以按 x 来保存,x 命令可以保存编辑好的文件哟。
也可以用到 wq 来保存,如果是 q! 则不保存哦,这点要自己谨记在心,这里我就保存一下 vi 编写的文件。
5. 然后查看,查看用到了cat 文件名哦。
1. 虚拟机网络的配置
进入:vi /etc/sysconfig/network-scripts/ifcfg-ens33
主机名配置
[root@node1 ~]# vi /etc/sysconfig/network
NETWORKING=yes
HOSTNAME=node1
IP 地址配置
[root@node1 ~]# vi /etc/sysconfig/network-scripts/ifcfg-eth0
域名映射
/etc/hosts 文件用于在通过主机名进行访问时做 ip 地址解析之用。所以,你想访问一个什么样的主机名,就需要把这个主机名和它对应的 ip 地址。
[root@node1 ~]# vi /etc/hosts
#### 在最后加上
192.168.52.201 node1
192.168.52.202 node2
192.168.52.203 node3
service network restart 重启网络
2. 设置虚拟机快照
一、基本命令
1.1 关机和重启
关机
shutdown -h now 立刻关机
shutdown -h 5 5 分钟后关机
poweroff 立刻关机
重启
shutdown -r now 立刻重启
shutdown -r 5 5 分钟后重启
reboot 立刻重启
1.2 帮助命令
--help 命令
shutdown --help:
ifconfig --help:查看网卡信息
man 命令(命令说明书)
man shutdown
注意:man shutdown 打开命令说明书之后,使用按键 q 退出
二、目录操作命令
命令:cd 目录cd / 切换到根目录
cd /usr 切换到根目录下的 usr 目录
cd ../ 切换到上一级目录 或者 cd ..
cd ~ 切换到 home 目录
cd - 切换到上次访问的目录
2.2 目录查看 ls [-al]
命令:ls [-al]ls 查看当前目录下的所有目录和文件
ls -a 查看当前目录下的所有目录和文件(包括隐藏的文件)
ls -l 或 ll 列表查看当前目录下的所有目录和文件(列表查看,显示更多信息)
ls /dir 查看指定目录下的所有目录和文件 如:ls /us
pwd 查看当前所有的路径
ls -s -h1 能列出文件大小
2.3 目录操作【增,删,改,查】
2.3.1 创建目录【增】 mkdir
命令:mkdir 目录mkdir aaa 在当前目录下创建一个名为 aaa 的目录
mkdir /usr/aaa 在指定目录下创建一个名为 aaa 的目录
删除目录或文件【删】rm
命令:rm [-rf] 目录删除文件:
rm 文件 删除当前目录下的文件
rm -f 文件 删除当前目录的的文件(不询问)删除目录:
rm -r aaa 递归删除当前目录下的 aaa 目录
rm -rf aaa 递归删除当前目录下的 aaa 目录(不询问)全部删除:
rm -rf 将当前目录下的所有目录和文件全部删除
rm -rf / 【自杀命令!慎用!慎用!慎用!】将根目录下的所有文件全部删除
目录修改【改】mv 和 cp
一、重命名目录 命令:mv 当前目录 新目录 例如:mv aaa bbb 将目录 aaa 改为 bbb 注意:mv 的语法不仅可以对目录进行重命名而且也可以对各种文件,压缩包等进行 重命名的操作二、剪切目录
命令:mv 目录名称 目录的新位置
示例:将 /usr/tmp 目录下的 aaa 目录剪切到 /usr 目录下面 mv /usr/tmp/aaa /usr
注意:mv 语法不仅可以对目录进行剪切操作,对文件和压缩包等都可执行剪切操作三、拷贝目录
命令:cp -r 目录名称 目录拷贝的目标位置 -r 代表递归
示例:将/usr/tmp 目录下的 aaa 目录复制到 /usr 目录下面 cp /usr/tmp/aaa /usr
注意:cp 命令不仅可以拷贝目录还可以拷贝文件,压缩包等,拷贝文件和压缩包时不 用写 -r 递归
2.3.4 搜索目录【查】find
命令:find 目录 参数 文件名称
示例:find /usr/tmp -name 'a*' 查找 /usr/tmp 目录下的所有以 a 开头的目录或文件
三、文件操作命令
3.1 文件操作【增,删,改,查】
3.1.1 新建文件【增】touch
命令:touch 文件名
示例:在当前目录创建一个名为 aa.txt 的文件 touch aa.txt
3.1.2 删除文件 【删】 rm
命令:rm -rf 文件名
3.1.3 修改文件【改】 vi 或 vim
【vi 编辑器的 3 种模式】
基本上 vi 可以分为三种状态,分别是命令模式(command mode)、插入模式(Insert mode)和底行模式(last line mode),
各模式的功能区分如下:
1) 命令行模式 command mode)
控制屏幕光标的移动,字符、字或行的删除,查找,移动复制某区段及进入 Insert mode 下,或者到 last line mode。
命令行模式下的常用命令:
【1】控制光标移动:↑,↓,j
【2】删除当前行:dd
【3】查找:/ 字符
【4】进入编辑模式:i o a
【5】进入底行模式::
2) 编辑模式(Insert mode)
只有在 Insert mode 下,才可以做文字输入,按「ESC」键可回到命令行模式。
编辑模式下常用命令:
【1】ESC 退出编辑模式到命令行模式;
3) 底行模式(last line mode)
将文件保存或退出 vi,也可以设置编辑环境,如寻找字符串、列出行号……等。
底行模式下常用命令:
【1】退出编辑: :q
【2】强制退出: :q!
【3】保存并退出: :wq
打开文件命令:vi 文件名
示例:打开当前目录下的 aa.txt 文件 vi aa.txt 或者 vim aa.txt注意:使用 vi 编辑器打开文件后,并不能编辑,因为此时处于命令模式,点击键盘 i/a/o 进入编辑模式。
编辑文件
使用 vi 编辑器打开文件后点击按键:i ,a 或者 o 即可进入编辑模式。
i: 在光标所在字符前开始插入
a: 在光标所在字符后开始插入
o: 在光标所在行的下面另起一新行插入保存或者取消编辑
保存文件:
第一步:ESC 进入命令行模式
第二步:: 进入底行模式
第三步:wq 保存并退出编辑取消编辑:
第一步:ESC 进入命令行模式
第二步:: 进入底行模式
第三步:q! 撤销本次修改并退出编辑
文件的查看【查】
文件的查看命令:cat/more/less/tail
cat:看最后一屏
示例:使用 cat 查看 /etc/sudo.conf 文件,只能显示最后一屏内容
cat sudo.conf
more:百分比显示
示例:使用 more 查看 /etc/sudo.conf 文件,可以显示百分比,回车可以向下一行,空格可以向下一页,q 可以退出查看
more sudo.conf
less:翻页查看
示例:使用 less 查看 /etc/sudo.conf 文件,可以使用键盘上的 PgUp 和 PgDn 向上 和向下翻页,q 结束查看
less sudo.conf
tail:指定行数或者动态查看
示例:使用 tail -10 查看 /etc/sudo.conf 文件的后 10 行,Ctrl+C 结束
tail -10 sudo.conf
3.2 权限
在 linux 中,为了数据的安全性,权限控制是十分重要的,在这里面可以细分成两个部分来理解他
linux 每一个用户都属于一个组,不能独立于组外。linux 的文件权限需要定义三个实体对它的权限
- 文件所有者
- 文件所在组
- 其他组
所有者
一般为文件的创建者,谁创建了该文件,就天然的成为该文件的所有者
可以使用chown【change owner】 用户名 文件名来修改文件的所有者,例如更改 error.log 的所有者为 enoch
chown enoch error.log #更改 error.log 的所有者为 enochchown enoch:home error.log #更改 error.log 的所有者和用户组为 enoch 与 home
chown .home error.log #更改 error.log 的用户组为 home
#在所有者和用户组中使用“.”也可以,但是由于很多用户喜欢使用小数点,可能造成系统误判,所以建议使用":"
所在组
当用户创建了一个文件后,这个文件的所在组就是该用户所在的用户组
可以使用 chgrp【change group】来改变文件的所在组
chgrp home error.log #修改文件的所在组为 home
其他组
除开所在组之外的其他组均为其他组
权限说明
当我们使用命令 ls -l 时候就会显示出改文件或者文件夹相对应的权限
drwx------ 2 www www 4096 May 5 19:35 www
drwxrwxrwx 2 root root 4096 May 5 16:51 wwwlogs
drwxr-xr-x 3 root root 4096 Jul 4 20:45 wwwroot
第一列规定了文件权限说明,共由十个字符分成四个部分,用 www 目录来说
[d] [rwx] [---] [---]1 234 567 890
1:代表这个文件是目录还是文件名其中 d 代表目录,如果是文件则为 -,更多的文件信息如下
1
2
3
4
5
6
|
d 目录文件。 l 符号链接(指向另一个文件,类似于瘟下的快捷方式)。 s 套接字文件。 b 块设备文件,二进制文件。 c 字符设备文件。 p 命名管道文件。 |
234:文件所有者的权限,rwx及为可读可写可执行
567:文件所有组的权限,--- 代表没有任何权限
890:除开所有者与所有组以外用户的权限,此处没有任何权限
修改权限
修改权限的命令是 chmod,而改变权限的方式分为两种
Linux 的文件基本权限只有九个,分别是 onwer,group,other 三种身份,所以我们可以用数字来代表权限,其中
r : 4
w : 2
x : 1
每种身份设置权限为数字的累加,比如将 error.log 文件设置成所有人都有 RWX 权限,则
chmod 777 error.log
符号改变法
四、压缩文件操作
4.1 打包和压缩
Windows 的压缩文件的扩展名 .zip/.rar
linux 中的打包文件:aa.tar
linux 中的压缩文件:bb.gz
linux 中打包并压缩的文件:.tar.gz
Linux 中的打包文件一般是以.tar结尾的,压缩的命令一般是以.gz结尾的。
而一般情况下打包和压缩是一起进行的,打包并压缩后的文件的后缀名一般.tar.gz。
命令:
tar -zcvf 打包压缩后的文件名(记得加后缀 ab.tar) 要打包的文件
其中:
z:调用 gzip 压缩命令进行压缩
c:打包文件
v:显示运行过程
f:指定文件名
示例:
打包并压缩 /usr/tmp 下的所有文件 压缩后的压缩包指定名称为 xxx.tar
tar -zcvf ab.tar aa.txt bb.txt
或:
tar -zcvf ab.tar *
4.2 解压
命令:tar [-zxvf] 压缩文件
其中:x:代表解压
示例:将 /usr/tmp 下的 ab.tar 解压到当前目录下
示例:将 /usr/tmp 下的 ab.tar 解压到根目录 /usr 下
tar -zxvf ab.tar -C /usr ------C 代表指定解压的位置
重定向 与管道
五、查找命令
5.1 grep(没啥用)
ps -ef | grep sshd 查找指定 ssh 服务进程
ps -ef | grep sshd | grep -v grep 查找指定服务进程,排除 gerp 身
ps -ef | grep sshd -c 查找指定进程个数
5.2 find
find 命令在目录结构中搜索文件,并对搜索结果执行指定的操作。
find 默认搜索当前目录及其子目录,并且不过滤任何结果(也就是返回所有文件),将它们全都显示在屏幕上。
使用实例:
find . -name "*.log" -ls 在当前目录查找以.log 结尾的文件,并显示详细信息。 find /root/ -perm 600 查找 /root/目录下权限为 600 的文件 find . -type f -name "*.log" 查找当目录,以.log 结尾的普通文件 find . -type d | sort 查找当前所有目录并排序 find . -size +100M 查找当前目录大于 100M 的文件
5.3 locate
locate 让使用者可以很快速的搜寻某个路径。默认每天自动更新一次,
所以使用 locate 命令查不到最新变动过的文件。为了避免这种情况,可以在使用 locate 之前,先使用updatedb 命令,
手动更新数据库。如果数据库中没有查询的数据,
则会报出 locate: can not stat () `/var/lib/mlocate/mlocate.db': No such file or directory 该错误!updatedb 即可!
yum -y install mlocate 如果是精简版 CentOS 系统需要安装 locate 命令
使用实例:
updatedb
locate /etc/sh 搜索 etc 目录下所有以 sh 开头的文件
locate pwd 查找和 pwd 相关的所有文件
5.4 whereis
whereis 命令是定位可执行文件、源代码文件、帮助文件在文件系统中的位置。
这些文件的属性应属于原始代码,二进制文件,或是帮助文件。
使用实例:
whereis ls 将和 ls 文件相关的文件都查找出来
5.5 which
which 命令的作用是在PATH 变量指定的路径中,搜索某个系统命令的位置,并且返回第一个搜索结果。
使用实例:
which pwd 查找 pwd 命令所在路径
which java 查找 path 中 java 的路径
六. 创建新用户
6.1 查看版本信息
先看下 Linux 的版本,输入命令 cat /etc/redhat-release
6.2 创建新用户
useradd [username]
,passwd [username]
,如下
到此为此新用户添加完成,切换到新用户进行登录
七、su、sudo
7.1 su
su 用于用户之间的切换。但是切换前的用户依然保持登录状态。
如果是 root 向普通或虚拟用户切换不需要密码,反之普通用户切换到其它任何用户都需要密码验证。
su test: 切换到 test 用户,但是路径还是 /root 目录
su - test : 切换到 test 用户,路径变成了 /home/test
su : 切换到 root 用户,但是路径还是原来的路径
su - : 切换到 root 用户,并且路径是 /root
su 不足:如果某个用户需要使用 root 权限、则必须要把 root 密码告诉此用户。
退出返回之前的用户:exit
6.2 sudo
sudo 是为所有想使用 root 权限的普通用户设计的。
可以让普通用户具有临时使用 root 权限的权利。只需输入自己账户的密码即可。
进入 sudo 配置文件命令:
vi /etc/sudoer或者 visudo
案例: 允许 hadoop 用户以 root 身份执行各种应用命令,需要输入 hadoop 用户的密码。 hadoop ALL=(ALL) ALL案例:
只允许 hadoop 用户以 root 身份执行 ls 、cat 命令,并且执行时候免输入密码。
配置文件中:
hadoop ALL=NOPASSWD: /bin/ls, /bin/cat
七、系统服务
service iptables status --查看 iptables 服务的状态 service iptables start --开启 iptables 服务 service iptables stop --停止 iptables 服务 service iptables restart --重启 iptables 服务chkconfig iptables off --关闭 iptables 服务的开机自启动
chkconfig iptables on --开启 iptables 服务的开机自启动
八、定时任务指令 crontab 配置
无法安装问题:
https://www.cnblogs.com/Rivend/p/11992679.html
一、安装[root@CentOS ~]# yum -y install vixie-cron
[root@CentOS ~]# yum -y install crontabs
说明:
vixie-cron 软件包是 cron 的主程序;
crontabs 软件包是用来安装、卸装、或列举用来驱动 cron 守护进程的表格的程序。二、配置
cron 是 linux 的内置服务,但它不自动起来,可以用以下的方法启动、关闭这个服务:
service crond start //启动服务
service crond stop //关闭服务
service crond restart //重启服务
service crond reload //重新载入配置
service crond status //查看 crontab 服务状态在 CentOS 系统中加入开机自动启动: chkconfig --level 345 crond on
cron 的主配置文件是 /etc/crontab,它包括下面几行:
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/# run-parts
01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly前四行是用来配置 cron 任务运行环境的变量。
SHELL 变量的值告诉系统要使用哪个 shell 环境(在这个例子里是 bash shell);
PATH 变量定义用来执行命令的路径。
cron 任务的输出被邮寄给 MAILTO 变量定义的用户名。
如果 MAILTO 变量被定义为空白字符串(MAILTO=""),电子邮件就不会被寄出。
HOME 变量可以用来设置在执行命令或脚本时使用的主目录。限制对 cron 的使用:
/etc/cron.allow 和 /etc/cron.deny 文件被用来限制对 cron 的使用。
这两个使用控制文件的格式都是每行一个用户。
两个文件都不允许空格。
如果使用控制文件被修改了,cron 守护进程(crond)不必被重启。
使用控制文件在每次用户添加或删除一项 cron 任务时都会被读取。无论使用控制文件中的规定如何,root 都总是可以使用 cron。
如果 cron.allow 文件存在,只有其中列出的用户才被允许使用 cron,并且 cron.deny 文件会被忽略。
如果 cron.allow 文件不存在,所有在 cron.deny 中列出的用户都被禁止使用 cron。三、crontab 命令
功能:设置计时器。
语法:crontab[-u < 用户名称 >][配置文件] 或 crontab [-u < 用户名称 >][-<span style="color: rgba(0, 0, 0, 1)">elr]
解释:cron 是一个常驻服务,它提供计时器的功能,让用户在特定的时间得以执行预设的指令或程序。
只要用户会编辑计时器的配置文件,就可以使 用计时器的功能。其配置文件格式如下
:Minute Hour Day Month DayOFWeek Command参数:
-e 编辑该用户的计时器设置。
-l 列出该用户的计时器设置。
-r 删除该用户的计时器设置。
-u< 用户名称 > 指定要设定计时器的用户名称。格式:
* * * * * command
分 时 日 月 周 命令第 1 列表示分钟 1~59 每分钟用 * 或者 */1 表示
第 2 列表示小时 1~23(0 表示 0 点)
第 3 列表示日期 1~31
第 4 列表示月份 1~12
第 5 列标识号星期 0~6(0 表示星期天)
第 6 列要运行的命令例子:
*/5 * * * * root ab -n 2000 http://60.217.229.252/250k.jpg上面例子表示每 5 分钟模拟用户访问 http://60.217.229.252/250k.jpg 2000 次
30 21 * * * /usr/local/etc/rc.d/lighttpd restart
上面的例子表示每晚的 21:30 重启 apache。45 4 1,10,22 * * /usr/local/etc/rc.d/lighttpd restart
上面的例子表示每月 1、10、22 日的 4 : 45 重启 apache。10 1 * * 6,0 /usr/local/etc/rc.d/lighttpd restart
上面的例子表示每周六、周日的 1 : 10 重启 apache。0,30 18-23 * * * /usr/local/etc/rc.d/lighttpd restart
上面的例子表示在每天 18 : 00 至 23 : 00 之间每隔 30 分钟重启 apache。0 23 * * 6 /usr/local/etc/rc.d/lighttpd restart
上面的例子表示每星期六的 11 : 00 pm 重启 apache。* */1 * * * /usr/local/etc/rc.d/lighttpd restart
每一小时重启 apache* 23-7/1 * * * /usr/local/etc/rc.d/lighttpd restart
晚上 11 点到早上 7 点之间,每隔一小时重启 apache0 11 4 * mon-wed /usr/local/etc/rc.d/lighttpd restart
每月的 4 号与每周一到周三的 11 点重启 apache0 4 1 jan * /usr/local/etc/rc.d/lighttpd restart
一月一号的 4 点重启 apache*/30 * * * * /usr/sbin/ntpdate 210.72.145.44
每半小时同步一下时间
补充:

history
目录结构介绍
硬盘、分区、cpu、内存、网络等常用命令
ip addr | grep inet
VIM 文本编辑器
Linux 下载软件
linux 下安装 python
第一步. 下载 python3 源码包
wget https://www.python.org/ftp/python/3.6.6/Python-3.6.6.tgz
这里下载的是 Python3.6.1,需要其他版本的可以移步这里https://www.python.org/downloads/查看,如下图:
第二步、解压
在进行解压之前先创建一个解压目录:
mkdir -p /usr/local/python3
接着把刚才下载的 Python3.6.1 安装包解压在该目录下:
tar -zxvf Python-3.6.6.tgz
第三步、编译安装
先进入到刚才解压的目录:
cd Python-3.6.6
然后配置一下安装目录,安装到我们之前创建的目录 /usr/local/python3 里,这样做的好处是下次想卸载软件直接卸载该目录下的就可以了:
./configure --prefix=/usr/local/python3
报错 ./configure 不能使用 请点击这里 https://www.cnblogs.com/Rivend/p/12052355.html
接着编译一下:
make
最后就是安装了:
make install
第四步、建立软链接
Linux 下的软链接其实就相当于 Windows 下的快捷方式:
ln -s /usr/local/python3/bin/python3 /usr/bin/python3
第五步、将 /usr/local/python3/bin 加入 PATH 环境变量
vim ~/.bash_profile
进入 vim 编辑页面,然后输入 i 指令加入如下内容:
export PATH=$PATH:$HOME/bin:/usr/local/python3/bin
接着按 [ESC] 退出编辑,输入 :wq 命令并按回车键保存退出。
(如果你不确定是否已经保存成功,可以再次输入指令 vim ~/.bash_profile 查看刚才的内容是否已经保存成功了,如果已经成功则直接输入指令:q 回车退出。)
第六步、测试是否安装成功
python3 -V
如果安装成功,会直接输出 Python3 的版本号。如下:
安装 PIP
Python 的一大优势就是拥有庞大的第三方支持库,而要使用这些库,就离不开Python 包管理工具 pip,所以我们现在马上下载一个。
安装 pip 之前先安装 setuptools
下载 setuptools:
wget --no-check-certificate https://pypi.python.org/packages/source/s/setuptools/setuptools-19.6.tar.gz#md5=c607dd118eae682c44ed146367a17e26
解压:
tar -zxvf setuptools-19.6.tar.gz
进入到解压盘:
cd setuptools-19.6
编译:
python3 setup.py build
安装:
python3 setup.py install
如果报错请点击这个 : https://www.cnblogs.com/Rivend/p/12052368.html
安装 pip
下载:
wget --no-check-certificate https://pypi.python.org/packages/source/p/pip/pip-8.0.2.tar.gz#md5=3a73c4188f8dbad6a1e6f6d44d117eeb
解压:
tar -zxvf pip-8.0.2.tar.gz
进入到解压盘:
cd pip-8.0.2
编译:
python3 setup.py build
安装:
python3 setup.py install
输入 "./ 你的 sh 文件名" 即可执行 一个文件
配置 pip3 的环境变量。
ln -s /usr/local/python3/bin/pip3 /usr/bin/pip3
如果报错: https://www.cnblogs.com/Rivend/p/12052381.html
python 导出项目所有依赖库, 在新环境中安装所有依赖库
# 导出项目的所有依赖库
pip3 freeze > requirements.txt
安装项目的所有依赖库
pip install -r requirements.txt
依赖库默认走的腾讯云镜像,所以下载安装会很快。
如果遇到了哪个库安装失败了,vi 编辑 requirements.txt 文件,在安装失败的 python 库所在行双击 d 删除该行,并把之前的行也都 dd 删除了,按 esc 输入:wq 保存并退出编辑。
然后再通过以上命令安装 requirements.txt 文件中剩下的 python 库即可。
注意:如果安装 sqlite3 的 python 库成功后依然引入失败,需要重新编译安装一下 python3:
cd Python-3.6.5
./configure --prefix=/usr/local/python3
make
make install
Django 应用部署
mysql 的安装
https://downloads.mysql.com/archives/community/
2、安装 mysql
tar -xvzf mysql-5.6.38-linux-glibc2.12-i686.tar.gz
3. 复制解压后的 mysql 目录到系统的本地软件目录:
执行命令:cp mysql-5.6.17-linux-glibc2.5-i686 /usr/local/mysql -r
注意:目录结尾不要加 /
添加系统 mysql 组和 mysql 用户:
执行命令:groupadd mysql 和 useradd -r -g mysql mysql
https://blog.csdn.net/wwwyuanliang10000/article/details/38661179
安装数据库:
进入安装 mysql 软件目录:执行命令 :
/mysql_software_56/scripts/mysql_install_db --defaults-file=/etc/my_5.6_3306.cnf --datadir=/my3306/data/ --user=mysql
修改当前目录拥有者为 mysql 用户:执行命令 chown -R mysql:mysql ./
安装数据库:执行命令 ./scripts/mysql_install_db --user=mysql
报错请看这里
https://blog.csdn.net/wwwyuanliang10000/article/details/38661179
修改当前目录拥有者为 root 用户:执行命令 chown -R root:root ./
修改当前 data 目录拥有者为 mysql 用户:执行命令 chown -R mysql:mysql data
到此数据库安装完毕
如果报错点击这里
https://www.cnblogs.com/jiuyachun/p/10096924.html
https://blog.csdn.net/wwwyuanliang10000/article/details/38661179