每日分享
The death of a dream is the day that you stop believing in the work it takes to get there.
不再相信自己能够成功,就是梦想破碎的时刻。
小闫语录:
支撑一个人前进的,莫过于信念。因为坚信黎明的曙光,所以未曾害怕黑暗。因为心中有你,所以前路尽是温暖。
shell(二)
1.shell流程控制
1.1简单流程控制语句
1.1.1if判断语句
首先我们通过一个示例来展示单分支if语句:
需求:如果输入的参数为 man
,那么输出您的性别为男。
#!/bin/bash if [ "$1" == "man" ] then echo "您的性别是:男" fi
我们执行上面的脚本文件:
ethanyan@ethanyan-PC:~$ bash if_test.sh man 您的性别是:男
我们可以通过一个条件的判断,得到不同情况下的结果吗?可以。下面我们就通过一个例子展示双分支if语句:
需求:输入参数 man
,输出您的性别为男,否则输出女性。
#!/bin/bash if [ "$1" == "man" ] then echo "您的性别是:男" else echo "您的性别是:女" fi
我们执行一下这个脚本文件:
ethanyan@ethanyan-PC:~$ bash if_test.sh man 您的性别是:男 ethanyan@ethanyan-PC:~$ bash if_test.sh woman 您的性别是:女
既然有单分支和双分支语句了,那么有多分支语句吗,就好像 elif
这种判断?有。下面我们就通过一个例子展示多分支if语句:
需求:输入参数 man
,输出您的性别为男;输入参数 woman
,输出女;输入其他,输出不知道。
#!/bin/bash if [ "$1" == "man" ] then echo "您的性别是:男" elif [ "$1" == "woman" ] then echo "您的性别是:女" else echo "您的性别,臣妾猜不到啊~" fi
我们执行脚本文件:
ethanyan@ethanyan-PC:~$ bash if_test.sh 您的性别,臣妾猜不到啊~ ethanyan@ethanyan-PC:~$ bash if_test.sh man 您的性别是:男 ethanyan@ethanyan-PC:~$ bash if_test.sh woman 您的性别是:女
综合示例-服务器
需求:我们通过传入的参数不同,实现不同的功能。
参数 | 执行效果 |
start | 服务器启动中... |
stop | 服务器关闭中... |
restart | 服务器重启中... |
脚本文件为:
ethanyan@ethanyan-PC:~$ bash if_test.sh stop 服务其正在关闭... ethanyan@ethanyan-PC:~$ bash if_test.sh start 服务器正在启动... ethanyan@ethanyan-PC:~$ bash if_test.sh restart 服务器正在重启... ethanyan@ethanyan-PC:~$ bash if_test.sh 脚本执行方式:bash if_test.sh [ start | stop | restart ]
1.1.2case选择语句
你有可能说:上面的if判断语句代码量有点多啊。那么我们就来简化一下,用到的就是 case
选择语句。
我们还是以上面的综合案例为例,进行改写。脚本文件如下:
#!/bin/bash case "$1" in "start") echo "服务器正在启动..." ;; "stop") echo "服务器正在关闭..." ;; "restart") echo "服务正在重启..." ;; *) echo "脚本的使用方法:bash $0 [ start | stop | restart ]" ;; esac
我们执行上面的脚本文件:
1. ethanyan@ethanyan-PC:~$ bash case_test.sh stop 2. 服务器正在关闭... 3. ethanyan@ethanyan-PC:~$ bash case_test.sh start 4. 服务器正在启动... 5. ethanyan@ethanyan-PC:~$ bash case_test.sh restart 6. 服务正在重启... 7. ethanyan@ethanyan-PC:~$ bash case_test.sh 8. 脚本的使用方法:bash case_test.sh [ start | stop | restart ] 1.1.3for循环语句
需求:循环遍历当前文件夹下的文件。
#!/bin/bash for i in $(ls ./) do echo "${i}" done
执行结果:
ethanyan@ethanyan-PC:~$ bash for_test case_test.sh for_test.sh if_test.sh ...
1.1.4while循环语句
格式:
while 条件 do 执行语句 done
注意:条件的类型:命令、[[ 字符串表达式 ]]、(( 数字表达式 ))
示例:a初始值为1,不断 +1
操作,直到a不小于5为止。
#!/bin/bash a=1 while [ "${a}" -lt 5 ] do echo "${a}" a=$((a+1)) done
执行上面的脚本文件:
ethanyan@ethanyan-PC:~$ bash while.sh 1 2 3 4
1.1.5until循环语句
格式:
until 条件 do 执行语句 done
注意:条件的类型:命令、[[ 字符串表达式 ]]、(( 数字表达式 ))
示例:a初始值为1,不断进行 +1
操作,直到a等于5为止。
#!/bin/bash a=1 until [ "${a}" -eq 5 ] do echo "${a}" a=$((a+1)) done
执行上面的脚本:
ethanyan@ethanyan-PC:~$ bash util.sh 1 2 3 4
2.函数
2.1简单函数
先来一个简单的函数,无参数。用于执行频繁的指令。我们封装一些常用指令,只需调用函数即可。
#
!/bin/bash # 定义函数 func1(){ echo "my name is ethanyan" } # 调用函数 func1 :<<! 我们可以在函数中封装常用指令 此处只是做一个简单的示例 !
执行上面的脚本:
ethanyan@ethanyan-PC:~$ bash fun1.sh my name is ethanyan
注意:在调用函数的时候没有括号。脚本文件中所有的标点符号均为英文状态下。
2.2函数传参
实现函数传参和函数体内调用参数,脚本文件示例:
#!/bin/bash func2(){ echo "my name is $1" } # 调用函数并传参 func2 ethanyan
执行脚本文件:
ethanyan@ethanyan-PC:~$ bash func2.sh my name is ethanyan
2.3脚本传参
实现脚本传参,函数调用。脚本文件示例:
#!/bin/bash func3(){ echo "my name is $1" } func3 $1
执行脚本:
ethanyan@ethanyan-PC:~$ bash func3.sh ethanyan my name is ethanyan
还有一种脚本传参的方式,这种情况在生产环境下使用:
#!/bin/bash name="$1" func4(){ echo "my name is $1" } func4 "${name}"
执行脚本:
ethanyan@ethanyan-PC:~$ bash func4.sh ethanyan my name is ethanyan
3.linux命令回顾
3.1压缩与解压缩-gz
文件压缩:
tar -zcvf 压缩后的文件名 压缩的文件
文件解压到当前路径:
tar -zxvf 要解压的文件
参数 | 作用 |
z | 指定压缩文件的格式为 tar.gz |
c | 压缩 |
v | 显示详细过程 |
f | 指定压缩文件 |
x | 解压 |
查看压缩文件内容:
zcat 压缩文件
上面压缩与解压缩的格式为常用的
gz
压缩格式。当然还有zip
和bz2
两种格式。
3.2文件传输
将本地的文件推送到远程的服务器:
scp 本地文件名用户名@ip:远程目录
将远程服务器上的文件拉取到本地:
scp 用户名@ip:远程文件本地目录
如果传输的是目录,不是文件,需要指定参数 -r
,如下:
scp -r 本地目录名用户名@ip:远程目录
3.3文件备份
可以使用 cp
命令来进行操作,但是为了避免放置新文件的时候,出现验证操作,常采用 mv
命令,如下:
mv test.txt test-$(date +%Y%m%d%H%M%S)
此处是将文件直接重命名而已,加了一个时间戳。当然你可以采用压缩进行备份;或者将文件复制一份,一份作为备份一份继续使用。根据场景自己选择。
3.3.1date命令:
格式:
date [option]
参数 | 作用 |
%F | 显示当前日期格式,%Y-%m-%d |
%T | 显示当前时间格式,%H:%M:%S |
使用效果:
ethanyan@ethanyan-PC:~$ date +%F 2019-04-05 ethanyan@ethanyan-PC:~$ date +%T 15:58:06
当然我们在给文件加时间戳的时候,希望是一串数字,没有特殊符号。下面代码即可实现:
date命令获取的都是当前系统的时间。
ethanyan@ethanyan-PC:~$ date +%Y%m%d 20190405 # 显示年月日 ethanyan@ethanyan-PC:~$ date +%H%M%S 160301 # 显示时分秒 ethanyan@ethanyan-PC:~$ date +%Y%m%d%H%M%S 20190405160403 # 显示年月日时分秒
4.环境部署
4.1基础目录环境
为了方便项目管理,需要创建基础环境目录。
起名要做到见名知意。
下面举一个例子:
1.创建基本目录:
mkdir ./data/{server,logs,backup,softs,virtual,scripts,codes}-p
-p
为创建层级目录。
2.查看创建的目录结构:
ethanyan@ethanyan-PC:~$ tree -L 1 ./data/ ./data/ ├── backup # 备份 ├── codes # 代码 ├── logs # 日志 ├── scripts # 脚本文件 ├── server # 服务 ├── softs # 软件 └── virtual # 虚拟环境
tree命令需要安装,用来查看目录树状结构。
-L
参数指定显示的层级,我们指定为显示1层。
4.2免密登录设置
我们在与主机进行文件传输的时候,每次链接都会进行密码验证,如果是手工的话,可以登录。自动化部署的时候,脚本却无能为力。那么有什么办法吗?答案就是进行免密钥认证操作。
方案思路:
1.本机生成密钥对;
2.对端机器使用公钥文件认证;
3.验证。
方案实施:
1.在本机生成密钥对:
ssh-keygen -t rsa
-t
:指定密钥类型。rsa
:密钥类型。
密钥目录:
/root/.ssh/
id_rsa
:私钥。id_rsa.pub
:公钥。
2.将 .pub
公钥文件复制到对端机器的目录中,并改名为 authorized_keys
,文件路径展示:
/root/.ssh/authorized_keys
3.在对端机器中,编辑 ssh
配置文件:
/etc/ssh/sshd_config
将下面一行的注释取消掉:
AuthorizedKeysFile %h/.ssh/authorized_keys
4.在对端机器重启ssh服务:
/etc/init.d/ssh restart
5.在本机进行连接,验证操作:
ssh root@192.168.8.15
4.3方案分析
需求:部署一个环境,支持django项目正常运行。
需求分析,部署方案:
1.进行django环境部署:
1.1 python虚拟环境 1.2 django环境部署 1.2.1 django软件安装 1.2.2 项目基本操作 1.2.3 应用基本操作 1.2.4 view和url配置 1.2.5问题:只有本机才能访问 1.2.6方案代理 --> nginx
2.nginx代理django:
2.1 nginx软件安装 2.1.1 pcre软件安装 2.1.2 nginx软件安装 2.1.3 nginx基本操作 2.2 nginx代理配置 2.2.1 目录结构查看 2.2.2 配置文件查看 2.2.3 编辑代理配置项
3.项目调试:
3.1 启动软件 3.1.1 启动django 3.1.2 启动nginx 3.2 整个项目调试
最后就是根据方案对项目进行部署。
5.生产脚本
5.1大型脚本编写
一般的脚本大家都会写了,那么对于线上服务器的大型脚本是如何实现的呢?我们先来看一下流程:
1.编写脚本框架。 (处处有框架,脚本也不例外,但是此框架需要自己实现)
2.用命令对脚本框架进行填充。
3.完善功能(增加日志功能;增加锁文件功能;增加主函数逻辑;增加参数安全措施)。
下面是编写一个简单的脚本框架,大家可以仿照书写:
#!/bin/bash # 功能:打包代码 # 脚本名:deploy.sh # 作者:ethanyan # 版本:V 0.1 # 联系方式:donnotcallme@163.com # 获取代码 get_code(){ echo "获取代码" } # 打包代码 tar_code(){ echo "打包代码" } # 传输代码 scp_code(){ echo "传输代码" } # 关闭应用 stop_serv(){ echo "关闭应用" echo "关闭nginx应用" echo "关闭django应用" } # 解压代码 untar_code(){ echo "解压代码" } # 放置代码 lay_code(){ echo "放置代码" echo "备份老文件" echo "放置新文件" } # 开启应用 start_serv(){ echo "开启应用" echo "开启django应用" echo "开启nginx应用" } # 检查 check(){ echo "检查项目" } # 部署函数 deploy_pro(){ get_code tar_code scp_code stop_serv untar_code lay_code start_serv check } # 主函数 main(){ deploy_pro } # 执行主函数 main
剩下的大家可以填充,完善等。
5.2生产脚本编写总结
- 生产简单脚本的编写流程:命令可执行-命令罗列-内容变量-功能函数-远程执行。
- 生产大型脚本的编写流程:脚本框架-命令填充-安全完善。
- 大型脚本的安全功能完善:由内到外,功能安全-流程安全。
- 掌握 脚本调试方法 语法-n ,追踪-x。
5.2.1简单脚本编写
- 手工执行的命令一定要可执行。
- 命令简单罗列。
- 固定的内容变量化。
- 功能函数化。
5.2.2复杂脚本编写
- 手工执行的命令一定要可执行。
- 根据发布流程编写脚本的框架。
- 将手工执行的命令填充到对应的框架函数内部。
- 增加日志功能,方便跟踪脚本历史执行记录。
- 主函数中逻辑流程控制好。
- 设计安全的方面:增加锁文件,保证代码发布的过程中不受干扰;判断输入参数数量;匹配输入参数;提供脚本帮助信息。
- 调试脚本。
5.2.3注意事项
- 命令一定要保证能正常执行。
- 成对的符号,要成对写,避免丢失。
- 函数调用。写好函数后,一定要在主函数中进行调用。
- 避免符号出现中文。
- 命令变量的写法一定要规范。
- 固定的内容一定要变量实现,方便以后更改。
- 日志的输出。
- 脚本的传参和函数的传参要区别对待。