SHELL自动化运维

版权声明:未经本人同意不得转载! https://blog.csdn.net/yanpenggong/article/details/83755800

第1章 shell脚本

1.1 shell 简介

shell 的定义

1. 在计算机科学中,Shell就是一个命令解释器。
2. shell是位于操作系统和应用程序之间,是他们二者最主要的接口,shell负责把应用程序的输入命令信息解释给操作系统,将操作系统指令处理后的结果解释给应用程序。

**总结:**shell就是在操作系统和应用程序之间的一个命令翻译工具。

1.2 shell的分类

shell分两大类

1. 图形界面:就是我们常说的桌面
2. 命令行:
    windows系统:cmd.exe	 命令提示字符
    linux系统:sh / csh / ksh / bash / ...

查看系统shell 信息

  1. 查看当前系统的shell类型
root@instance-nl5v4j4n:/home/kungs# echo $SHELL
/bin/bash
  1. 查看当前系统环境支持的shell
root@instance-nl5v4j4n:/home/kungs# cat /etc/shells
# /etc/shells: valid login shells
/bin/sh
/bin/dash
/bin/bash
/bin/rbash
/usr/bin/tmux
/usr/bin/screen

1.3 shell脚本

1. shell 使用方式

1. 手工方式:
	手工敲击键盘,在shell的命令行输入命令,按Enter后,执行通过键盘输入的命令,然后shell返回并显示命令执行的结果.
重点:逐行输入命令、逐行进行确认执行

2. 脚本方式:
	就是说我们把手工执行的命令a,写到一个脚本文件b中,然后通过执行脚本b,达到执行命令a的效果.

2. shell 脚本定义

当可执行的Linux命令或语句不在命令行状态下执行,而是通过一个文件执行时,称文件为shell脚本。

3. shell 脚本示例

# 1. 手工方法 
root@instance-nl5v4j4n:/home/kungs# echo 'kungs'
kungs

# 2. 脚本方法
root@instance-nl5v4j4n:/home/kungs# cat kungs.sh 
#!/bin/bash
# 这是一个临时测试脚本
echo 'kungs'
echo 'kungs love you'

第2章 SHELL基础知识

2.1 shell脚本

2.1.1 创建脚本

创建工具:vi/vim
脚本命名:shell脚本的命名要有意义,方便我们通过脚本名,来知道此文件用途
脚本内容:各种可执行的命令
注释内容:
	1.单行注释:除了首行的'#'不是注释外,其他行内容的首个字符是'#',
	2.多行注释:多行注释有两种方法:':<<! ... !'':<<字符 ... 字符'

实例:

root@instance-nl5v4j4n:/home/kungs# cat zhushi.sh 
#!/bin/bash
# 单行注释

echo '下一行是多行注释'
:<<!
echo '1'
echo '2'
echo '3'
!
echo '4'
root@instance-nl5v4j4n:/home/kungs# bash zhushi.sh 
下一行是多行注释
4

2.1.2 脚本执行

shell 执行方式

bash/path/to/script-name 或  /bin/bash /path/to/script-name    (强烈推荐使用)
/path/to/script-name  或  ./script-name    (当前路径下执行脚本)
source script-name  或  . script-name    (注意“.“点号)

执行说明:

1、脚本文件本身没有可执行权限或者脚本首行没有命令解释器时使用的方法,我们推荐用bash执行。
	使用频率:☆☆☆☆☆
2、脚本文件具有可执行权限时使用。
	使用频率:☆☆☆☆
3、使用source或者.点号,加载shell脚本文件内容,使shell脚本内容环境和当前用户环境一致。
    使用频率:☆☆☆
    使用场景:环境一致性

2.1.3 脚本开发规范

1、脚本命名要有意义,文件后缀是.sh
2、脚本文件首行是而且必须是脚本解释器
	#!/bin/bash
3、脚本文件解释器后面要有脚本的基本信息等内容
	- 脚本文件中尽量不用中文注释;尽量用英文注释,防止本机或切换系统环境后中文乱码的困扰
	- 常见的注释信息:脚本名称、脚本功能描述、脚本版本、脚本作者、联系方式等
4、脚本文件常见执行方式:bash 脚本名
5、脚本内容执行:从上到下,依次执行
6、代码书写优秀习惯;
	1)成对内容的一次性写出来,防止遗漏。
		如:(){}[]''、``、""
	2)[]中括号两端要有空格,书写时即可留出空格[    ],然后再退格书写内容。
	3)流程控制语句一次性书写完,再添加内容
7、通过缩进让代码易读;(即该有空格的地方就要有空格)

2.2 变量

2.2.1 什么是变量

变量名	: 不变的
变量值	: 变化的

2.2.2 本地变量

本地变量是什么?

本地变量:在当前系统的某个环境下才能生效的变量,作用范围小。

本地变量包含两种:普通变量命令变量

1. 普通变量:

普通变量的定义方式有如下三种:

方式一:
    变量名=变量值
    重点:变量值必须是一个整体,中间没有特殊字符       
方式二:
    变量名='变量值'
    重点:我看到的内容,我就输出什么内容   
方式三:
    变量名="变量值"
    重点:如果变量值范围内,有可以解析的变量A,那么首先解析变量A,将A的结果和其他内容组合成一个整体,重新赋值给变量B
习惯:
数字不加引号,其他默认加双引号

例:

root@instance-nl5v4j4n:/home/kungs# kungs=nihao222
root@instance-nl5v4j4n:/home/kungs# echo $kungs
nihao222
root@instance-nl5v4j4n:/home/kungs# kungs='nihao333'
root@instance-nl5v4j4n:/home/kungs# echo $kungs
nihao333
root@instance-nl5v4j4n:/home/kungs# kungs="hello555"
root@instance-nl5v4j4n:/home/kungs# echo $kungs
hello555

2. 命令变量( 熟练)

命令变量有两种定义方式

方式一:
    变量名=`命令`
    echo $变量名
    注意:
    ` 是反引号
 
方式二(常用的方法):
	变量名=$(命令)
	echo $变量名

实例:

root@instance-nl5v4j4n:/home/kungs# dir=`pwd`
root@instance-nl5v4j4n:/home/kungs# echo $dir
/home/kungs
root@instance-nl5v4j4n:/home/kungs# pwd
/home/kungs
root@instance-nl5v4j4n:/home/kungs# echo $(pwd)
/home/kungs

2.2.3 全局变量

在当前系统的所有环境下都能生效的变量。

查看全局环境变量命令

env  只显示全局变量

定义全局变量

方法一:
    变量=export 变量
方法二(常用):
	export 变量=

2.2.4 变量查看和取消

1. 查看变量:

方法 实例
$变量名 echo $kungs
“$变量名” echo “$kungs”
${变量名} echo ${kungs}
“${变量名}” echo “${kungs}”

2. 取消变量

unset 变量名
例:
unset kungs

2.2.5 shell内置变量

1. 和脚本文件有关

符号 意义
$0 获取当前执行的shell脚本文件名,包括脚本路径
$n 获取当前执行的shell脚本的第n个参数值,n=1,…,9,当n为0时表示脚本的文件名,如果n大于9就要用大括号括起来${10}
$# 获取当前shell命令行中参数的数量
$? 获取执行上一个指令的返回值(0为成功,非0为失败)

实例:

NgandeMacBook-Pro:kungs_shells kungs$ cat get_name1.sh 
#!/bin/bash
# $0 获取当前脚本的名称
echo "脚本名称是;get_name.sh"
echo "当前获取脚本的名称是;$0"
NgandeMacBook-Pro:kungs_shells kungs$ bash get_name1.sh 
脚本名称是;get_name.sh
当前获取脚本的名称是;get_name1.sh

NgandeMacBook-Pro:kungs_shells kungs$ cat get_args.sh 
#!/bin/bash
# $n  获取第n个位置的参数
echo "第一个位置参数是:$1"
NgandeMacBook-Pro:kungs_shells kungs$ bash get_args.sh
第一个位置参数是:
NgandeMacBook-Pro:kungs_shells kungs$ bash get_args.sh a
第一个位置参数是:a
NgandeMacBook-Pro:kungs_shells kungs$ cat get_args1.sh 
#!/bin/bash
# $n  获取第n个位置的参数
echo "第一个位置参数是:$1"
echo "第二个位置参数是:$2"
echo "第三个位置参数是:$3"
echo "第四个位置参数是:$4"
NgandeMacBook-Pro:kungs_shells kungs$ bash get_args1.sh a b c d
第一个位置参数是:a
第二个位置参数是:b
第三个位置参数是:c
第四个位置参数是:d

获取文件执行或者命令执行的返回状态值:

NgandeMacBook-Pro:kungs_shells kungs$ bash hello
bash: hello: No such file or directory
NgandeMacBook-Pro:kungs_shells kungs$ echo $?
127
NgandeMacBook-Pro:kungs_shells kungs$ ls
ceshi-11.sh	ceshi.sh	get_num.sh	moren2.sh	zhengque
ceshi-all	cuowu		grep.txt	nihao.txt	zhushi.sh
ceshi-err	get_args.sh	kungs.sh	sed.txt		zhushi.sh-1
ceshi-ok	get_name1.sh	moren1.sh	tree1
NgandeMacBook-Pro:kungs_shells kungs$ echo $?
0

2. 字符串精确截取

格式:${变量名:起始位置:截取长度}

实例:

NgandeMacBook-Pro:~ kungs$ file=sdfjoermrelcdgid
NgandeMacBook-Pro:~ kungs$ echo $file
sdfjoermrelcdgid
NgandeMacBook-Pro:~ kungs$ echo ${file:0:5}
sdfjo
NgandeMacBook-Pro:~ kungs$ echo ${file::5}
sdfjo
NgandeMacBook-Pro:~ kungs$ echo ${file:5:5}
ermre
NgandeMacBook-Pro:~ kungs$ echo ${file:0-5}
cdgid
NgandeMacBook-Pro:~ kungs$ echo ${file:0-5:3}
cdg

3. 默认值相关

场景一:

1. 变量a如果有内容,那么就输出a的变量值
2. 变量a如果没有内容,那么就输出默认的内容

格式:${变量名:-默认值}

实例:

如果我输入的参数为空,那么输出内容是 "您选择的套餐是: 套餐1"
如果我输入的参数为n,那么输出内容是 "您选择的套餐是: 套餐 n" 
NgandeMacBook-Pro:kungs_shells kungs$ vim moren1.sh
NgandeMacBook-Pro:kungs_shells kungs$ cat moren1.sh 
#!/bin/bash
# 默认值场景1 有条件的默认值

# 定义一个本地变了,接受脚本传参
a="$1"
echo " 您选择的套餐是:${a:-1} 套餐"
NgandeMacBook-Pro:kungs_shells kungs$ bash moren1.sh 
 您选择的套餐是:1 套餐
NgandeMacBook-Pro:kungs_shells kungs$ bash moren1.sh 3
 您选择的套餐是:3 套餐

场景二:

无论变量a是否有内容,都输出默认值

格式:${变量名+默认值}

实例:

不管我说那个输出内容是 多少,都输出 那个输出内容是 22 岁
NgandeMacBook-Pro:kungs_shells kungs$ vim moren2.sh
NgandeMacBook-Pro:kungs_shells kungs$ cat moren2.sh 
#!/bin/bash
# 默认值场景2,默认值强制生效

# 定义一个本地变了,接受脚本传入的参数
a="$1"

echo "输出内容是:${a+22} 岁"
NgandeMacBook-Pro:kungs_shells kungs$ bash moren2.sh 
输出内容是:22 岁
NgandeMacBook-Pro:kungs_shells kungs$ bash moren2.sh 3
输出内容是:22 岁

第3章 SHELL进阶

内容

1. 测试语句
2. 表达式(条件+计算)
3. linux常见富豪和命令

3.1 表达式

要使Shell脚本程序具备一定的“逻辑能力”,面临的第一个问题就是:区分不同的情况以确定执行何种操作。

学习解决这个问题方法:测试语句

3.1.1 测试语句

Shell环境根据命令执行后的返回状态值($?)来判断是否执行成功,当返回值为0,表示成功,值为其他时,表示失败。使用专门的测试工具—test命令,可以对特定条件进行测试,并根据返回值来判断条件是否成立(返回值0为成立)

测试语句形式

A: test 条件表达式,注意后面的等式要有空格

NgandeMacBook-Pro:kungs_shells kungs$ test 1 = 1
NgandeMacBook-Pro:kungs_shells kungs$ echo $?
0
NgandeMacBook-Pro:kungs_shells kungs$ test 1 = 3
NgandeMacBook-Pro:kungs_shells kungs$ echo $?
1

B: [ 条件表达式 ]

格式注意:以上两种方法的作用完全一样,后者为常用。

但后者需要注意方括号[、]与条件表达式之间至少有一个空格。

test[] 的意思一样:

  • 条件成立,状态返回值是0

  • 条件不成立,状态返回值是1

NgandeMacBook-Pro:kungs_shells kungs$ [ 1 = 1 ]
NgandeMacBook-Pro:kungs_shells kungs$ echo $?
0
NgandeMacBook-Pro:kungs_shells kungs$ [ 1 = 2 ]
NgandeMacBook-Pro:kungs_shells kungs$ echo $?
1

操作注意:

[]两侧为什么要有空格

NgandeMacBook-Pro:kungs_shells kungs$ [-x /bin/bash ]
-bash: [-x: command not found
NgandeMacBook-Pro:kungs_shells kungs$ [ 1 = 2]
-bash: [: missing `]'

可以看到:

两侧没有空格,就会报错,为什么呢?因为你不合规范

3.1.2 条件表达式

测试的结果使用 echo $? 来查看

1. 逻辑表达式:逻辑表达式一般用于判断多个条件之间的依赖关系。

常见的逻辑表达式有: &&||

1). &&

命令1 && 命令2

1. 如果命令1执行成功,那么我才执行命令2     --夫唱妇随
2. 如果命令1执行失败,那么命令2也不执行:

实例:

NgandeMacBook-Pro:kungs_shells kungs$ [ 1 = 1 ] && echo "条件成立"
条件成立
NgandeMacBook-Pro:kungs_shells kungs$ [ 1 = 2 ] && echo "条件成立"
NgandeMacBook-Pro:kungs_shells kungs$ 

2). ||

命令1 || 命令2

1. 如果命令1执行成功,那么命令2不执行           -- 对着干
2. 如果命令1执行失败,那么命令2执行             

​ 实例:

NgandeMacBook-Pro:kungs_shells kungs$ [ 1 = 2 ] || echo "条件不成立"
条件不成立
NgandeMacBook-Pro:kungs_shells kungs$ [ 1 = 1 ] || echo "条件不成立"
NgandeMacBook-Pro:kungs_shells kungs$ 

2. 文件表达式

1). -f 判断输入内容是否是一个文件

NgandeMacBook-Pro:kungs_shells kungs$ ls
get_args.sh	get_num.sh	moren1.sh	zhushi.sh
get_name1.sh	kungs.sh	moren2.sh	zhushi.sh-1
NgandeMacBook-Pro:kungs_shells kungs$ [ -f moren1.sh ]
NgandeMacBook-Pro:kungs_shells kungs$ echo $?
0
NgandeMacBook-Pro:kungs_shells kungs$ [ -f moren1.sh ] && echo "它是一个普通文件"
它是一个普通文件
NgandeMacBook-Pro:kungs_shells kungs$ [ -f moren1.shsad ] && echo "它是一个普通文件"
NgandeMacBook-Pro:kungs_shells kungs$ 

2). -d 判断输入内容是否是一个目录

NgandeMacBook-Pro:kungs_shells kungs$ ls
get_args.sh	get_num.sh	moren1.sh	tree1		zhushi.sh-1
get_name1.sh	kungs.sh	moren2.sh	zhushi.sh
NgandeMacBook-Pro:kungs_shells kungs$ [ -d tree1 ]
NgandeMacBook-Pro:kungs_shells kungs$ echo $?
0
NgandeMacBook-Pro:kungs_shells kungs$ [ -d tree1 ] && echo "是一个目录"
是一个目录
NgandeMacBook-Pro:kungs_shells kungs$ [ -d tree1 ] || echo "不是一个目录"
NgandeMacBook-Pro:kungs_shells kungs$ [ -d tree11 ] || echo "不是一个目录"
不是一个目录

3). -x 判断输入内容是否可执行

NgandeMacBook-Pro:kungs_shells kungs$ ls -al
total 64
-rw-r--r--   1 kungs  staff   156 10 29 11:13 moren1.sh
NgandeMacBook-Pro:kungs_shells kungs$ [ -x moren1.sh ]
NgandeMacBook-Pro:kungs_shells kungs$ echo $?
1
NgandeMacBook-Pro:kungs_shells kungs$ [ -x moren1.sh ] || chmod +x moren1.sh 
NgandeMacBook-Pro:kungs_shells kungs$ ls -alh
total 64
-rwxr-xr-x   1 kungs  staff   156B 10 29 11:13 moren1.sh
NgandeMacBook-Pro:kungs_shells kungs$ [ -x moren1.sh ] && ./moren1.sh 
 您选择的套餐是:1 套餐

3. 数值操作符(-eq-gt-ltne)

主要根据给定的两个值,判断第一个与第二个数的关系,如是否大于、小于、等于第二个数。常见选项如下:

n1 -eq n2    相等
n1 -gt n2    大于
n1 -lt n2    小于
n1 -ne n2    不等于

实例:

NgandeMacBook-Pro:kungs_shells kungs$ [ 1 -eq 1 ]
NgandeMacBook-Pro:kungs_shells kungs$ echo $?
0
NgandeMacBook-Pro:kungs_shells kungs$ [ 1 -gt 1 ]
NgandeMacBook-Pro:kungs_shells kungs$ echo $?
1
NgandeMacBook-Pro:kungs_shells kungs$ [ 1 -lt 2 ]
NgandeMacBook-Pro:kungs_shells kungs$ echo $?
0
NgandeMacBook-Pro:kungs_shells kungs$ [ 1 -ne 2 ]
NgandeMacBook-Pro:kungs_shells kungs$ echo $?
0

4. 字符串比较

str1 == str2          str1和str2字符串内容一致
str1 != str2          str1和str2字符串内容不一致,!表示相反的意思

实例:

判断字符是否内容一致

NgandeMacBook-Pro:kungs_shells kungs$ [ a == a ]
NgandeMacBook-Pro:kungs_shells kungs$ echo $?
0
NgandeMacBook-Pro:kungs_shells kungs$ [ a == ab ]
NgandeMacBook-Pro:kungs_shells kungs$ echo $?
1
NgandeMacBook-Pro:kungs_shells kungs$ a=hello
NgandeMacBook-Pro:kungs_shells kungs$ b=nobody
NgandeMacBook-Pro:kungs_shells kungs$ echo $a
hello
NgandeMacBook-Pro:kungs_shells kungs$ echo $b
nobody
NgandeMacBook-Pro:kungs_shells kungs$ [ "${a}" == "${b}" ]
NgandeMacBook-Pro:kungs_shells kungs$ echo $?
1
NgandeMacBook-Pro:kungs_shells kungs$ [ "${a}" != "${b}" ]
NgandeMacBook-Pro:kungs_shells kungs$ echo $?
0

3.1.3 计算表达式($(( 计算表达式 ))let)

计算表达式,简单来说就是对具体的内容进行算数计算

格式:

方式一:
	$(( 计算表达式 ))
方式二:
	let
	注意:$(())中只能用+-*/和()运算符,并且只能做整数运算

计算表达式

实例:

$((变量名a+1)) 注意:表达式范围内,空格不限制

NgandeMacBook-Pro:kungs_shells kungs$ echo $((1+1))
2
NgandeMacBook-Pro:kungs_shells kungs$ echo $((2+2))
4
NgandeMacBook-Pro:kungs_shells kungs$ echo $((2*3))
6

let 注意:表达式必须是一个整体,中间不能出现空格等特殊字符

NgandeMacBook-Pro:kungs_shells kungs$ let a=1+1
NgandeMacBook-Pro:kungs_shells kungs$ echo $a
2
NgandeMacBook-Pro:kungs_shells kungs$ let a=1+5
NgandeMacBook-Pro:kungs_shells kungs$ echo $a
6
NgandeMacBook-Pro:kungs_shells kungs$ let a=a+1
NgandeMacBook-Pro:kungs_shells kungs$ echo $a
7
NgandeMacBook-Pro:kungs_shells kungs$ a=$((a+7))
NgandeMacBook-Pro:kungs_shells kungs$ echo $a
14

3.2 Linux常见符号

重定向符号、管道符、其他符号

3.2.1 重定向符号( >>>)

shell脚本中有两种常见的重定向符号 >>>

1. >

作用:将符号左侧的内容,以**覆盖**的方式输入到右侧文件中

实例:

NgandeMacBook-Pro:kungs_shells kungs$ echo 'nihao'
nihao
NgandeMacBook-Pro:kungs_shells kungs$ echo 'nihao' > nihao.txt
NgandeMacBook-Pro:kungs_shells kungs$ cat nihao.txt 
nihao
NgandeMacBook-Pro:kungs_shells kungs$ echo 'nihaoma' > nihao.txt
NgandeMacBook-Pro:kungs_shells kungs$ cat nihao.txt 
nihaoma

2. >>

作用:将符号左侧的内容,以**追加**的方式输入到右侧文件的末尾行中

实例:

NgandeMacBook-Pro:kungs_shells kungs$ cat nihao.txt 
nihaoma
NgandeMacBook-Pro:kungs_shells kungs$ echo 'hellonihao' >> nihao.txt
NgandeMacBook-Pro:kungs_shells kungs$ cat nihao.txt 
nihaoma
hellonihao
NgandeMacBook-Pro:kungs_shells kungs$ echo 'hellonihao1' >> nihao.txt
NgandeMacBook-Pro:kungs_shells kungs$ cat nihao.txt 
nihaoma
hellonihao
hellonihao1

3.2.2 管道符(|)

| 这个就是管道符,传递信息使用的

使用格式:命令1 | 命令2

管道符左侧命令1 执行后的结果,**传递**给管道符右侧的命令2使用

实例:

NgandeMacBook-Pro:kungs_shells kungs$ env |grep SHELL
SHELL=/bin/bash

3.2.3 其他符号(&)

1. 后台展示符号 &

定义:& 就是将一个命令从前台转到后台执行

使用格式:命令 &

NgandeMacBook-Pro:kungs_shells kungs$ sleep 10 &
[1] 2483
NgandeMacBook-Pro:kungs_shells kungs$ 
NgandeMacBook-Pro:kungs_shells kungs$ 
NgandeMacBook-Pro:kungs_shells kungs$ 
NgandeMacBook-Pro:kungs_shells kungs$ 
[1]+  Done                    sleep 10
NgandeMacBook-Pro:kungs_shells kungs$ sleep 10 &
[1] 2489
NgandeMacBook-Pro:kungs_shells kungs$ ps aux |grep sleep
kungs             2493   0.0  0.0  2432804    772 s000  S+    3:58下午   0:00.00 grep sleep
kungs             2489   0.0  0.0  2432788    636 s000  S     3:58下午   0:00.00 sleep 10

2. 全部信息符号 2>&1

符号详解:
    1 表示正确输出的信息  1>>
    2 表示错误输出的信息  2>>
	2>&1 代表所有输出的信息

符号实例

1).标准正确输出实例:

NgandeMacBook-Pro:kungs_shells kungs$ cat nihao.txt 1>> zhengque
NgandeMacBook-Pro:kungs_shells kungs$ cat zhengque
nihaoma
hellonihao
hellonihao1

2).标准错误输出实例:

NgandeMacBook-Pro:kungs_shells kungs$ lll
-bash: lll: command not found
NgandeMacBook-Pro:kungs_shells kungs$ dgsa
-bash: dgsa: command not found
NgandeMacBook-Pro:kungs_shells kungs$ dgsa 2>> cuowu
NgandeMacBook-Pro:kungs_shells kungs$ cat cuowu 
-bash: dgsa: command not found

综合演示实例:

NgandeMacBook-Pro:kungs_shells kungs$ cat ceshi.sh 
#!/bin/bash
echo "下一条错误命令"
sahdaosfdofgaovavav
NgandeMacBook-Pro:kungs_shells kungs$ bash ceshi.sh 
下一条错误命令
ceshi.sh: line 3: sahdaosfdofgaovavav: command not found
NgandeMacBook-Pro:kungs_shells kungs$ bash ceshi.sh 1>> ceshi-ok 2>> ceshi-err
NgandeMacBook-Pro:kungs_shells kungs$ cat ceshi-ok 
下一条错误命令
NgandeMacBook-Pro:kungs_shells kungs$ cat ceshi-err 
ceshi.sh: line 3: sahdaosfdofgaovavav: command not found
NgandeMacBook-Pro:kungs_shells kungs$ bash ceshi.sh 1>> ceshi-11 2>> ceshi-11
NgandeMacBook-Pro:kungs_shells kungs$ cat ceshi-11 
下一条错误命令
ceshi.sh: line 3: sahdaosfdofgaovavav: command not found
NgandeMacBook-Pro:kungs_shells kungs$ bash ceshi.sh >> ceshi-all 2>&1
NgandeMacBook-Pro:kungs_shells kungs$ cat ceshi-all 
下一条错误命令
ceshi.sh: line 3: sahdaosfdofgaovavav: command not found

3. linux 系统垃圾桶

/dev/null是linux下的一个设备文件,这个文件类似于一个垃圾桶,特点是:容量无限大,常常把其设置到此垃圾桶里,避免后期再去删除相关文件。

NgandeMacBook-Pro:kungs_shells kungs$ ls /dev/null
/dev/null
NgandeMacBook-Pro:kungs_shells kungs$ bash ceshi.sh >> /dev/null 2>&1

3.3 常见命令详解(grepsedawkfind)

shell脚本中经常使用的linux命令:grepsedawkfind

3.3.1 grep命令详解

grep命令是常用的一个强大的文本搜索命令。

格式:

grep [参数][关键字] <文件名>

注意:

我们在查看某个文件的内容的时候,是需要有<文件名>

grep命令在结合|(管道符)使用的情况下,后面的<文件名>是没有的

可以通过 grep --help 查看grep的帮助信息

参数详解

    -c:只输出匹配行的计数。
    -n:显示匹配行及行号。
    -v:显示不包含匹配文本的所有行。
NgandeMacBook-Pro:kungs_shells kungs$ cat grep.txt 
hello aaa
hello aaa
hello AAA
hello bbb
hello ccc
NgandeMacBook-Pro:kungs_shells kungs$ grep -c aaa grep.txt
2
NgandeMacBook-Pro:kungs_shells kungs$ grep aaa grep.txt 
hello aaa
hello aaa
NgandeMacBook-Pro:kungs_shells kungs$ grep -c hello grep.txt
5
NgandeMacBook-Pro:kungs_shells kungs$ grep -n aaa grep.txt 
1:hello aaa
2:hello aaa
NgandeMacBook-Pro:kungs_shells kungs$ grep -n ccc grep.txt 
5:hello ccc
NgandeMacBook-Pro:kungs_shells kungs$ grep -v aaa grep.txt 
hello AAA
hello bbb
hello ccc
NgandeMacBook-Pro:kungs_shells kungs$ grep -nr aaa *
grep.txt:1:hello aaa
grep.txt:2:hello aaa

3.3.2 sed命令详解

sed 行文件编辑工具。因为它编辑文件是以行为单位的。

格式

sed [参数] '<匹配条件> [动作]'[文件名]
mac版:
sed [参数] '' '<匹配条件> [动作]'[文件名]

注意:可以通过 sed —help 查看grep的帮助信息

参数详解:

1. 参数为空 表示sed的操作效果,实际上不对文件进行编辑
2. -i   表示对文件进行编辑
3. 注意:mac版的bash中使用 -i参数,必须在后单独加个东西(''): -i ''

**匹配条件:**数字行号 或 关键字匹配

关键字匹配格式:'/关键字/'

注意:隔离符号/ 可以更换成 @#等符号

根据情况使用,如果关键字和隔离符号有冲突,就更换成其他的符号即可。

例:

root@instance-nl5v4j4n:/home/kungs# cat sed.txt 
insert_1
hello SED SED SED
news_add
hello sed sed sed
hello SED SED SED
root@instance-nl5v4j4n:/home/kungs# sed -i '2s\SED\sed\2' sed.txt 
root@instance-nl5v4j4n:/home/kungs# cat sed.txt 
insert_1
hello SED sed SED
news_add
hello sed sed sed
hello SED SED SED
root@instance-nl5v4j4n:/home/kungs# sed -i '2s@SED@sed@2' sed.txt 
root@instance-nl5v4j4n:/home/kungs# cat sed.txt 
insert_1
hello SED sed sed
news_add
hello sed sed sed
hello SED SED SED
root@instance-nl5v4j4n:/home/kungs# sed -i '5s@SED@sed@2' sed.txt 
root@instance-nl5v4j4n:/home/kungs# cat sed.txt 
insert_1
hello SED sed sed
news_add
hello sed sed sed
hello SED sed SED

动作详解

-a      在匹配到的内容下一行增加内容
-i      在匹配到的内容上一行增加内容
-d      删除匹配到的内容
-s      替换匹配到的内容

注意:上面的动作应该在参数为-i的时候使用,不然的话不会有效果

1. 替换命令(行号、列号、全体)

格式:sed -i [替换格式][文件名]

sed -i '行号s#原内容#替换内容#原内容第几个(默认空:1,全部:g)' 文件名 
例:
sed -i '3s#SED#sed#g' sed.txt # 第三行所有的SED改为sed

实例:

NgandeMacBook-Pro:kungs_shells kungs$ cat sed.txt 
hello sed sed sed
hello sed sed sed
hello sed sed sed
hello sed sed sed

# 文件第一行的第一个(默认) 'sed' 替换为 'SED'
NgandeMacBook-Pro:kungs_shells kungs$ sed -i '1s#sed#SED#' sed.txt 
NgandeMacBook-Pro:kungs_shells kungs$ cat sed.txt 
hello SED sed sed
hello sed sed sed
hello sed sed sed
hello sed sed sed

# 文件所有行的第二个'sed'替换为'SED'
NgandeMacBook-Pro:kungs_shells kungs$ sed -i 's#sed#SED#2' sed.txt 
NgandeMacBook-Pro:kungs_shells kungs$ cat sed.txt 
hello SED sed SED
hello sed SED sed
hello sed SED sed
hello sed SED sed

# 文件第三行的第二个'sed'替换为'SED'
NgandeMacBook-Pro:kungs_shells kungs$ sed -i '3s#sed#SED#2' sed.txt 
NgandeMacBook-Pro:kungs_shells kungs$ cat sed.txt 
hello SED sed SED
hello sed SED sed
hello sed SED SED
hello sed SED sed

# 文件所有行的所有'sed'替换为'SED'
NgandeMacBook-Pro:kungs_shells kungs$ sed -i 's#sed#SED#g' sed.txt 
NgandeMacBook-Pro:kungs_shells kungs$ cat sed.txt 
hello SED SED SED
hello SED SED SED
hello SED SED SED
hello SED SED SED

# 文件第三行所有的'SED'替换为'sed'
NgandeMacBook-Pro:kungs_shells kungs$ sed -i '3s#SED#sed#g' sed.txt 
NgandeMacBook-Pro:kungs_shells kungs$ cat sed.txt 
hello SED SED SED
hello SED SED SED
hello sed sed sed
hello SED SED SED

2. 增加操作

**目的1:**在指定行号的下一行增加内容;

**目的2:**在指定行号的上一行增加内容;

格式:

# 在某行号的下一行增加内容
sed -i '行号a\增加的内容' 文件名
# 增加多行,可以在行号位置写个范围值,彼此间用逗号隔开,例:在1~3每行的下一行都增加内容
sed -i '1,3a\增加内容' 文件名

# 在指定行号的前一行增加内容
sed -i '行号i\增加的内容' 文件名
# 行号前增加多行,可以在行号位置写个范围值,彼此间使用逗号隔开,例:在1~3每行的上一行都增加内容
sed -i '1,3i\增加内容' 文件名


注意:在mac终端中有所区别,不然会报下面的错
NgandeMacBook-Pro:kungs_shells kungs$ sed -i '' '1a\add-1\' sed.txt 
sed: 1: "1a\add-1\": extra characters after \ at the end of a command
NgandeMacBook-Pro:kungs_shells kungs$ sed -i '' "1,3a\tongshi-2" sed.txt
sed: 1: "1,3a\tongshi-2": command a expects up to 1 address(es), found 2

正确做法:下面是mac中的正确方法
# 在某行号的下一行增加内容
NgandeMacBook-Pro:kungs_shells kungs$ sed -i '' "1a\\
> 增加的内容\\
> " 文件名
注意:这里增加多行目前没有办法去解决

实例:

root@instance-nl5v4j4n:/home/kungs# cat sed.txt 
hello SED SED SED
hello SED SED SED
hello sed sed sed
hello SED SED SED
root@instance-nl5v4j4n:/home/kungs# sed -i '1a\add_news' sed.txt 
root@instance-nl5v4j4n:/home/kungs# cat sed.txt 
hello SED SED SED
add_news
hello SED SED SED
hello sed sed sed
hello SED SED SED
root@instance-nl5v4j4n:/home/kungs# sed -i '1,3a\news_add' sed.txt 
root@instance-nl5v4j4n:/home/kungs# cat sed.txt 
hello SED SED SED
news_add
add_news
news_add
hello SED SED SED
news_add
hello sed sed sed
hello SED SED SED

root@instance-nl5v4j4n:/home/kungs# sed -i '1i\insert_1' sed.txt 
root@instance-nl5v4j4n:/home/kungs# cat sed.txt 
insert_1
hello SED SED SED
news_add
add_news
news_add
hello SED SED SED
news_add
hello sed sed sed
hello SED SED SED
root@instance-nl5v4j4n:/home/kungs# sed -i '1,3i\insert_news' sed.txt 
root@instance-nl5v4j4n:/home/kungs# cat sed.txt 
insert_news
insert_1
insert_news
hello SED SED SED
insert_news
news_add
add_news
news_add
hello SED SED SED
news_add
hello sed sed sed
hello SED SED SED

3. 删除操作

格式:

# 指定行号删除
sed -i '行号d' 文件名
# 如果删除多行,可以在行号位置多写几个行号,彼此间使用逗号隔开,例:1-3行删除
sed -i '1,3d' 文件名

实例:

root@instance-nl5v4j4n:/home/kungs# cat sed.txt 
insert_news
insert_1
insert_news
hello SED SED SED
insert_news
news_add
add_news
news_add
hello SED SED SED
news_add
hello sed sed sed
hello SED SED SED
root@instance-nl5v4j4n:/home/kungs# sed -i '1d' sed.txt 
root@instance-nl5v4j4n:/home/kungs# cat sed.txt 
insert_1
insert_news
hello SED SED SED
insert_news
news_add
add_news
news_add
hello SED SED SED
news_add
hello sed sed sed
hello SED SED SED
root@instance-nl5v4j4n:/home/kungs# sed -i '2,7d' sed.txt 
root@instance-nl5v4j4n:/home/kungs# cat sed.txt 
insert_1
hello SED SED SED
news_add
hello sed sed sed
hello SED SED SED

3.3.3 awk命令详解

awk是一个功能非常强大的文档编辑工具,不仅能以行为单位还能以列为单位处理文件。

命令格式:

awk [参数] '[ 动作]' [文件名]

常见参数:-F 指定行的分隔符

常见动作:

print  显示内容
    $0  显示当前行所有内容
    $n  显示当前行的第n列内容,如果存在多个$n,它们之间使用逗号(,)隔开

常见内置变量

FILENAME   当前输入文件的文件名,该变量是只读的
NR         指定显示行的行号
NF         输出最后一列的内容
OFS        输出格式的列分隔符,缺省是空格
FS         输入文件的列分融符,缺省是连续的空格和Tab

实例:

root@instance-nl5v4j4n:/home/kungs# cat awk.txt 
hello awk awk awk awk
hello awk awk awk awk
root@instance-nl5v4j4n:/home/kungs# awk '{print $0}' awk.txt 
hello awk awk awk awk
hello awk awk awk awk
root@instance-nl5v4j4n:/home/kungs# awk '{print $1}' awk.txt 
hello
hello
root@instance-nl5v4j4n:/home/kungs# awk '{print $1$3}' awk.txt 
helloawk
helloawk
root@instance-nl5v4j4n:/home/kungs# awk '{print $1,$3}' awk.txt 
hello awk
hello awk

# 打印第1列第3列内容,显示行的行号
root@instance-nl5v4j4n:/home/kungs# awk '{print NR,$1,$3}' awk.txt 
1 hello awk
2 hello awk
root@instance-nl5v4j4n:/home/kungs# awk 'NR==1 {print $1,$3}' awk.txt 
hello awk
root@instance-nl5v4j4n:/home/kungs# sed -i 's# #:#g' awk.txt 
root@instance-nl5v4j4n:/home/kungs# cat awk.txt 
hello:awk:awk:awk:awk
hello:awk:awk:awk:awk
root@instance-nl5v4j4n:/home/kungs# awk '{print $1,$3}' awk.txt 
hello:awk:awk:awk:awk 
hello:awk:awk:awk:awk 
root@instance-nl5v4j4n:/home/kungs# awk -F ':' '{print $1,$3}' awk.txt 
hello awk
hello awk
root@instance-nl5v4j4n:/home/kungs# awk -F ':' 'BEGIN{OFS="@"} {print $1,$3}' awk.txt 
hello@awk
hello@awk

3.3.4 find命令

格式:

find [路径][参数] [关键字]

参数

-name  按照文件名查找文件。
-perm  按照文件权限来查找文件
-user  按照文件属主来查找文件。
-group 按照文件所属的组来查找文件。
-type  查找某一类型的文件,
    诸如:
    b - 块设备文件
    d - 目录
    c -字符设备文件
    p - 管道文件
    l - 符号链接文件
    f- 普通文件。
-size n:[c] 查找文件长度为n块的文件,带有c时表示文件长度以字节计。
-depth:在查找文件时,首先查找当前目录中的文件,然后再在其子目录中查找。
 -mindepth n:在查找文件时,查找当前目录中的第n层目录的文件,然后再在其子目录中查找。
! : 表示取反

例:

NgandeMacBook-Pro:kungs_shells kungs$ ls
ceshi-11	ceshi.sh	get_num.sh	moren2.sh	zhengque
ceshi-all	cuowu		grep.txt	nihao.txt	zhushi.sh
ceshi-err	get_args.sh	kungs.sh	sed.txt		zhushi.sh-1
ceshi-ok	get_name1.sh	moren1.sh	tree1
NgandeMacBook-Pro:kungs_shells kungs$ find ./ -type d
./
.//tree1
.//tree1/tree2
.//tree1/tree2/tree3
NgandeMacBook-Pro:kungs_shells kungs$ find ./ -type d -name "tree*"
.//tree1
.//tree1/tree2
.//tree1/tree2/tree3
NgandeMacBook-Pro:kungs_shells kungs$ find ./ -type f -name "moren*"
.//moren1.sh
.//moren2.sh

第4章 流程控制

在shell的语句中,流程控制主要分为两种:

1. 简单流程控制语句:选择和循环
2. 复杂流程控制语句:函数

4.1 简单流程控制语句

4.1.1 单分支if语句

语法格式:单一条件,只有一个输出

if [ 条件 ]
then
	指令
fi

实例:

root@instance-nl5v4j4n:/home/kungs# cat danif.sh 
#!/bin/bash
# 单if语句的使用场景

# 定义一个本地变量,用于接受脚本执行时候的参数
a="$1"

if [ "${a}" == "nan" ]
then
  echo "男"
fi
root@instance-nl5v4j4n:/home/kungs# bash danif.sh nan
男
root@instance-nl5v4j4n:/home/kungs# bash danif.sh nand
root@instance-nl5v4j4n:/home/kungs# 

4.1.2 双分支if语句

语法格式: 一个条件,两种结果

if [ 条件 ]
then
	指令1
else
	 指令2
fi

实例:

root@instance-nl5v4j4n:/home/kungs# cat shuangif.sh 
#!/bin/bash
# 双if语句的使用场景

# 定义一个本地变量,用于接受脚本执行时候的参数
a="$1"

if [ "${a}" == "nan" ]
then
  echo "男"
else
  echo "女"
fi
root@instance-nl5v4j4n:/home/kungs# bash shuangif.sh nan
男
root@instance-nl5v4j4n:/home/kungs# bash shuangif.sh nand

4.1.3 多分支if语句

语法格式:n个条件,n+1个结果

if [ 条件 ]
then
	指令1
elif[ 条件2 ]
then
	指令2
else
	指令3
fi

实例:

root@instance-nl5v4j4n:/home/kungs# cat duoif.sh 
#!/bin/bash
# 多if语句的使用场景

# 定义一个本地变量,用于接受脚本执行时候的参数
a="$1"

if [ "${a}" == "nan" ]
then
  echo "男"
elif [ "${a}" == "nv" ]
then
  echo "女"
else
  echo "未知"
fi
root@instance-nl5v4j4n:/home/kungs# bash duoif.sh nan
男
root@instance-nl5v4j4n:/home/kungs# bash duoif.sh nv
女
root@instance-nl5v4j4n:/home/kungs# bash duoif.sh nvd
未知

-------------------

多if语句生产场景:服务的启动

​ 要求脚本执行需要有参数,通过传入参数来实现不同的功能。

参数和功能:

参数 执行效果
start 服务启动中…
stop 服务关闭中…
restart 服务重启中…
* 脚本 X.sh 使用方式 X.sh [ start|stop|restart ]

实例:

root@instance-nl5v4j4n:/home/kungs# cat duoif_serv.sh 
#!/bin/bash
# 多if语句生产案例,服务脚本

# 定义一个本地变量,接受传入的参数
a="$1"

if [ "${a}" == "start" ]
then
  echo "服务启动中..."
elif [ "${a}" == "stop" ]
then
  echo "服务关闭中..."
elif [ "${a}" == "restart" ]
then
  echo "服务重启中..."
else
  echo "脚本$0 的使用方式:$0 [ start|stop|restart ]"
fi
root@instance-nl5v4j4n:/home/kungs# bash duoif_serv.sh 
脚本duoif_serv.sh 的使用方式:duoif_serv.sh [ start|stop|restart ]
root@instance-nl5v4j4n:/home/kungs# bash duoif_serv.sh start
服务启动中...
root@instance-nl5v4j4n:/home/kungs# bash duoif_serv.sh stop
服务关闭中...
root@instance-nl5v4j4n:/home/kungs# bash duoif_serv.sh restart
服务重启中...

4.1.4 case选择语句

多if语句使用的时候,代码量很多,而且整体看起来确实有那么一丁点乱。Case语句:简明。

case 语句格式

case 变量名 in
	值1)
        指令1
        ;;
	值2)
        指令2
        ;;
	值3)
        指令3
        ;;
esac

实例:

root@instance-nl5v4j4n:/home/kungs# cat case.sh 
#!/bin/bash
# case语法演示

# 定义一个本地变量,接受脚本传入的参数
a="$1"

case "${a}" in 
  start)
    echo "服务启动中..."
    ;;
  stop)
    echo "服务关闭中..."
    ;;
  restart)
    echo "服务重启中..."
    ;;
  *)
    echo "脚本 $0 的使用方式:$0 [ start|stop|restart ]"
    ;;
esac
root@instance-nl5v4j4n:/home/kungs# bash case.sh 
脚本 case.sh 的使用方式:case.sh [ start|stop|restart ]
root@instance-nl5v4j4n:/home/kungs# bash case.sh start
服务启动中...
root@instance-nl5v4j4n:/home/kungs# bash case.sh stop
服务关闭中...
root@instance-nl5v4j4n:/home/kungs# bash case.sh restart
服务重启中...

---------------

4.1.5 for循环语句

遍历列表,循环指定的所有元素,循环完毕之后就推出

语法格式

forin 列表
do
   执行语句
done

注意:

1. ”for”循环总是接收 “in” 语句之后的某种类型的字列表
2. 执行次数和list列表中常数或字符串的个数相同,当循环的数量足够了,就自动退出

实例:

root@instance-nl5v4j4n:/home/kungs# cat for.sh 
#!/bin/bash
# for 语句演示

for i in $(ls /home/kungs)
do
  echo "/home/kungs 目录下的文件:${i}"
done
root@instance-nl5v4j4n:/home/kungs# ls
awk.txt        elasticsearch-2.4.6        __MACOSX          shuangif.sh
case.sh        elasticsearch-2.4.6.zip    meiduo_01         test01
danif.sh       fdfs_client-py-master.zip  mysql_slave       zhushi.sh
data.tar.gz    for.sh                     pi.py
duoif_serv.sh  goods_data.sql             requirements.txt
duoif.sh       kungs.sh                   sed.txt
root@instance-nl5v4j4n:/home/kungs# bash for.sh 
/home/kungs 目录下的文件:awk.txt
/home/kungs 目录下的文件:case.sh
/home/kungs 目录下的文件:danif.sh
/home/kungs 目录下的文件:duoif_serv.sh
/home/kungs 目录下的文件:duoif.sh
/home/kungs 目录下的文件:for.sh
/home/kungs 目录下的文件:kungs.sh
/home/kungs 目录下的文件:sed.txt
/home/kungs 目录下的文件:shuangif.sh
/home/kungs 目录下的文件:zhushi.sh

4.1.6 while循环语句

语法格式:只要条件满足,就一直循环下去

while 条件
do
   执行语句
done

其中条件的类型:
命令、[[ 字符串表达式 ]](( 数字表达式 ))

实例:

root@instance-nl5v4j4n:/home/kungs# cat while.sh 
#!/bin/bash
# while 语法演示

# 定义一个本地变量
a=1

while [ "${a}" -lt 5 ]
do
  echo "${a}"
  a=$((a+1))
done
root@instance-nl5v4j4n:/home/kungs# bash while.sh 
1
2
3
4

4.1.7 until循环语句

语法格式:只要条件不满足,就一直循环下去

until 条件
do
   执行语句
done

条件的类型:
命令、[[ 字符串表达式 ]]、(( 数字表达式 ))

实例:

root@instance-nl5v4j4n:/home/kungs# cat until.sh 
#!/bin/bash
# until 语句演示

# 定义一个本地变量
a=1

# until主框架
until [ "${a}" -eq 3 ]
do
  echo "${a}"
  a=$((a+1))
done
root@instance-nl5v4j4n:/home/kungs# bash until.sh 
1
2

4.2 复杂流程控制语句

​ 函数就是我们的复杂流程控制语句

4.2.1 函数基础知识

函数是什么?

函数就是将某些命令组合起来实现某一特殊功能的方式,是脚本编写中非常重要的一部分。

1. 简单函数格式:

定义函数:

函数名(){
	函数体
}

​ 调用函数:

函数名

实例:

root@instance-nl5v4j4n:/home/kungs# cat func.sh 
#!/bin/bash
# 简单函数定义

# 定义函数
function1(){
  echo "welcome to China"
}
# 调用函数
function1
root@instance-nl5v4j4n:/home/kungs# bash func.sh 
welcome to China

2. 传参函数格式:

传参数

函数名 参数 

函数体调用参数:

函数名(){
	函数体 $n
}

​ 注意:类似于shell内置变量中的位置参数

实例:

root@instance-nl5v4j4n:/home/kungs# cat func_canshu.sh 
#!/bin/bash
# 传参函数定义

# 定义函数
function1(){
  echo "welcome to China $1"
}
# 调用函数
function1 kungs
function1 kungs1
root@instance-nl5v4j4n:/home/kungs# bash func_canshu.sh 
welcome to China kungs
welcome to China kungs1

4.2.2 函数实践

简单函数定义和调用示例

root@instance-nl5v4j4n:/home/kungs# cat func_canshu.sh 
#!/bin/bash
# 传参函数定义和调用

# 定义函数
function1(){
  echo "welcome to China $1"
}
# 调用函数
# function1 kungs
function1 "$1"
root@instance-nl5v4j4n:/home/kungs# bash func_canshu.sh kung00
welcome to China kung00

函数传参和函数体内调用参数示例

root@instance-nl5v4j4n:/home/kungs# cat func_canshu.sh 
#!/bin/bash
# 传参函数定义和调用

# 定义函数
function1(){
  echo "welcome to China $1"
}
# 调用函数
function1 kungs
root@instance-nl5v4j4n:/home/kungs# bash func_canshu.sh
welcome to China kung

函数调用脚本传参

root@instance-nl5v4j4n:/home/kungs# cat func_canshu.sh 
#!/bin/bash
# 传参函数定义和调用

# 定义函数
function1(){
  echo "welcome to China $1"
}
# 调用函数
function1 "$1"
root@instance-nl5v4j4n:/home/kungs# bash func_canshu.sh kung00
welcome to China kung00

脚本传多参,函数分别调用示例

root@instance-nl5v4j4n:/home/kungs# cat func_jiaoben.sh 
#!/bin/bash
# 传参函数定义和调用

# 定义函数
function1(){
  echo "welcome to China $1"
}
# 调用函数
function1 "$1"
function1 "$2"
root@instance-nl5v4j4n:/home/kungs# bash func_jiaoben.sh kungs8 kungs9
welcome to China kungs8
welcome to China kungs9

---------------

4.3 第一阶段综合案例

需求

1、zonghe.sh 脚本执行时候需要添加参数才能执行

参数和功能详情如下:

参数 执行效果
start 服务启动中…
stop 服务关闭中…
restart 服务重启中…
* 脚本帮助信息…

2、参数的数量有限制,只能是1个,多余一个会提示脚本的帮助信息

3、帮助信息使用函数来实现

信息内容:脚本 zonghe.sh 使用方式 zonghe.sh [ start|stop|restart ]

知识点分析:

1、zonghe.sh 脚本执行时候需要添加参数才能执行
	脚本传参、case语句
2、参数的数量有限制,只能是1个,多余一个会提示脚本的帮助信息
	参数数量、条件表达式(验证+数字)、if语句
3、帮助信息使用函数来实现
	函数定义+调用
4、if语句和case语句嵌套
	if语句在外,case语句在内

脚本编写流程

1、先写主流程框架
2、完善函数功能 
3、完善需求功能

实例:

root@instance-nl5v4j4n:/home/kungs# cat zonghe.sh
#!/bin/bash
# 脚本主框架

# 动议本地变量,接受脚本传参
a="$1"

# 编写脚本帮助信息
usage(){
  echo "脚本 $0 使用方式 $0 [ start|stop|restart ]"
}

# 脚本主框架
if [ "$#" -eq 1 ]
then
  case "${a}" in
    start)
      echo "服务启动中..."
      ;;
    stop)
      echo "服务关闭中..."
      ;;
    restart)
      echo "服务重启中..."
      ;;
    *)
      usage
      ;;
    esac
else
  usage
fi
root@instance-nl5v4j4n:/home/kungs# bash zonghe.sh 
脚本 zonghe.sh 使用方式 zonghe.sh [ start|stop|restart ]
root@instance-nl5v4j4n:/home/kungs# bash zonghe.sh start
服务启动中...
root@instance-nl5v4j4n:/home/kungs# bash zonghe.sh stop
服务关闭中...
root@instance-nl5v4j4n:/home/kungs# bash zonghe.sh restart
服务重启中...
root@instance-nl5v4j4n:/home/kungs# bash zonghe.sh red
脚本 zonghe.sh 使用方式 zonghe.sh [ start|stop|restart ]

第5章 代码发布

5.1 代码发布

发布什么?

​ 代码:经过测试,功能完善,没有问题的代码

发布到哪里?

​ 服务器:所有人都能访问的到的一台服务器(有公网IP)

​ idc机房、阿里云、亚马逊、腾讯云、华为云、…

发布的效果?

​ web网页:对外展示

发布方式

1. 手工发布代码:
    慢
    干扰因素多
    不安全
2. 脚本发布代码:
    快
    干扰因素少
    安全

5.2 代码发布流程

获取代码 —> 打包代码 —> 传输代码 —> 停止应用 —> 解压代码 —> 放置代码 —> 开启代码 —> 开启应用 —> 检查效果 —> 对外访问

0. 部署场景:

两台主机做部署动作

在这里插入图片描述

注意:部署的文件就是两台主机右上角的红色内容

1. 获取代码

​ 代码仓库

1. 集中式的:  svn
2. 分布式的:  git

区别:
svn的几乎所有操作命令,都集中在我和代码仓库服务器处于网络连接状态。
git的几乎所有操作命令,可以在本地完成,和代码仓库服务器是否连接无关。

公司的代码仓库:

私有仓库: gitlab
内部服务器或者公网服务器

仓库权限

只有项目的开发人员才有权限,项目之外的人没有权限

代码权限:

开发、管理、查看

提交的方式:

代码版本号

2. 打包代码

在这里插入图片描述

目的:

1. 减少传输文件数量
2. 减小传输文件大小
3. 增强传输速率

常见打包方式:

1. windows:  zip、rar...
2. linux:    tar、zip...

3. 传输代码

在这里插入图片描述

​ 传输方式:

1. 有网情况下:多种方式:git、ftp、**scp**、共享挂载 cp、rsync

2. 没有网情况下:物理方式: U盘或者硬盘

4. 停止应用

代码所在的服务用到了什么应用,就关闭什么应用

关闭的顺序:先关闭离客户近的,后关闭离客户远的

5. 解压代码

tar xf 

6. 放置代码

避免我们在放置代码过程中,对老文件造成影响

放置代码分为两步:1. 备份老文件  2. 放置新文件。
注意:
    两个文件的名称是一样的,只是内容不同
    对整个应用项目来说,两个文件没有区别

1) 备份原文件

在这里插入图片描述

2) 放置新文件

在这里插入图片描述

7. 开启应用

刚才关闭了什么应用就开启什么应用

开启的顺序:先开启离客户远的,后开启离客户近的

8. 检查效果

查看浏览器效果或者netstat -tnulp查看系统开放的端口

5.3 技术关键点

1. 文件的压缩和解压

文件的压缩

压缩格式:
tar zcvf 压缩后的文件名  将要压缩的文件

文件的解压

解压格式:
tar xf 压缩后的文件名

命令参数详解

z   指定压缩文件的格式为 tar.gz
c   表示压缩
v   显示详细过程
f   指定压缩文件
x   解压

查看压缩文件内容

zcat 压缩文件

2. 文件的传输

​ scp传输工具:

命令格式:
	scp  要传输的文件       要放置的位置
将本地文件推送到远程主机
	scp python.tar.gz [email protected]:/root/
将远程主机的文件拉取到本地
	scp [email protected]:/root/python.tar.gz ./
远端主机文件放置位置的表示形式:
	远程连接的用户@远程主机:远程主机的目录路径
远端主机文件位置的表示形式:
	远程连接的用户@远程主机:远程主机的文件路径

3. 文件的备份

文件的备份要有一定的标志符号,使用目前通用的时间戳形式来表示

命令格式:date [option]
常见参数:
    %F  显示当前日期格式,%Y-%m-%d
    %T  显示当前时间格式,%H:%M:%S

演示效果:

# 显示当前日期
root@instance-nl5v4j4n:/home/kungs# date +%F
2018-10-31

# 显示当前时间
root@instance-nl5v4j4n:/home/kungs# date +%T
20:42:54

根据上面的参数介绍,我们可以指定命令显示的格式,

年月日:date +%Y%m%d
时分秒:date +%H%M%S

实例:

显示当前日期
root@instance-nl5v4j4n:/home/kungs# date +%Y%m%d
20181031

显示当前时间
root@instance-nl5v4j4n:/home/kungs# date +%H%M%S
204546

指定时间戳格式:

年月日时分秒:date +%Y%m%d%H%M%S

实例:

指定的时间戳格式
root@instance-nl5v4j4n:/home/kungs# date +%Y%m%d%H%M%S
20181031204724

备份命令效果格式:

方式一:复制备份
	cp hello hello-$(date +%Y%m%d%H%M%S)
方式二:移动备份
	mv hello hello-$(date +%Y%m%d%H%M%S)

注意:我们为了避免在放置新文件时候,出现验证操作,我们确定采用方式二

---------------

实例操作:

1、在主机1上创建一个目录/data/tar-ceshi/,在目录里面创建两个文件,内容分别如下:

文件名          内容
file1.txt      file1
file2.txt      file2

2、对目录tar-ceshi进行压缩

3、对目录tar-ceshi进行时间戳备份

4、将压缩包文件传输到远端主机2

5、在主机2上解压 压缩包文件

6、在主机2上修改压缩包文件内容。然后再次压缩

7、在主机1上拉取主机2的压缩包文件

8、使用命令查看压缩包文件的内容

# 答案
1.在主机1上创建一个目录/data/tar-ceshi/,在目录里面创建两个文件及内容
    mkdir /data/tar-ceshi -p
    cd /data
    echo 'file1' > tar-ceshi/file1.txt
    echo 'file2' > tar-ceshi/file2.txt
2. 对目录tar-ceshi进行压缩
	tar zcvftar-ceshi.tar.gz tar-ceshi
3. 对目录tar-ceshi进行时间戳备份
	mv tar-ceshitar-ceshi-$(date +%Y%m%d%H%M%S)
4. 将压缩包文件传输到远端主机2
	scptar-ceshi.tar.gz [email protected]:/tmp
5. 在主机2上解压 压缩包文件
    cd /tmp
    tar xf tar-ceshi.tar.gz
6. 在主机2上修改压缩包文件内容。然后再次压缩
    echo 'file3' >> tar-ceshi/file1.txt
    tar zcvf tar-ceshi-1.tar.gz tar-ceshi
7. 在主机1上拉取主机2的压缩包文件
	[email protected]:/tmp/tar-ceshi-1.tar.gz ./
8. 使用命令查看压缩包文件的内容
	zcat tar-ceshi-1.tar.gz

第六章 环境部署

需要有一个项目的基础环境,然后在这个基础环境上,再根据项目需求搭建一个能让项目代码正常运行的环境。

6.1 基础环境

6.1.1 基础目录环境

创建基本目录

root@instance-nl5v4j4n:/data# mkdir /data/{server,logs,backup,softs,virtual,scripts,codes}
root@instance-nl5v4j4n:/data# ls /data/
backup  codes  logs  scripts  server  soft  virtual

查看

root@instance-nl5v4j4n:/data# tree -L 1 /data/
/data/
├── backup
├── codes
├── logs
├── scripts
├── server
├── softs
└── virtual

7 directories, 0 files

6.1.2 主机网络环境

问题:

我们上面进行文件传输的时候,发现一个问题,每次进行文件传输都需要进行密码验证,解决办法:

主机间免密码认证

主机间免密码认证步骤:

1. 本机生成密钥对
2. 对端机器使用公钥文件认证
3. 验证

代码操作:

1. 生成秘钥对

ssh-keygen -t rsa
其中:   -t   指定秘钥的类型  
		rsa  秘钥类型         
秘钥目录:/root/.ssh/
    私钥     id_rsa      钥匙
    公钥     id_rsa.pub  锁

2. 将公钥发送到要远程登陆的服务器上

scp -P 端口 ~/.ssh/id_rsa.pub 用户名@对方ip:~/.ssh/

3. 在服务器建立authorized_keys映射

cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

4. 在服务端打开authorized_keys修改配置

vi /etc/ssh/sshd_config

#1. 本地是linux系统(屏蔽mac操作):
AuthorizedKeysFile   %h/.ssh/authorized_keys
#2. 本地是mac系统(屏蔽linux操作):
AuthorizedKeysFile .ssh/authorized_keys

5. 本地验证操作

ssh [email protected]

# 若是不成功
用chmod 检查.shh权限
    .ssh 应为700
    authorized_keys 为600

6.2 方案分析

6.2.1 需求

​ 部署一个环境,支持我们的django项目正常运行

6.2.2 需求分析

2、python环境  --->  3、python虚拟环境
1、django环境部署
	4、django软件安装
	5、项目基本操作
	6、应用基本操作
	7、view和url配置
		8、问题:只有本机能访问
		9、方案代理---- 10、nginx
11、nginx实现代理
	13、pcre软件安装
	12、nginx软件安装
	14、nginx基本操作
	15、nginx代理的配置
		16、目录结构
		17、查看配置文件
		18、找到对应的代理配置项
19、启动django
20、启动nginx
21、整个项目调试

6.2.3 部署方案

一、django环境部署
    1.1 python虚拟环境
    1.2 django环境部署
        1.2.1 django软件安装
        1.2.2 项目基本操作
        1.2.3 应用基本操作
        1.2.4 view和url配置
二、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.1 启动软件
        3.1.1 启动django
        3.1.2 启动nginx
    3.2 整个项目调试

6.3 项目环境部署

6.3.1 python 虚拟环境

1. 虚拟环境安装

apt-getinstall python-virtualenv -y
或者
pip3 install virtualenv

2. 虚拟环境基本操作

# 创建
virtualenv -p /usr/bin/python3.5 venv
# 进入
source venv/bin/activate
# 退出
deactivate
# 删除
rm-rf venv

6.3.2 django环境

1. django 软件安装

# 注意:先进入虚拟环境
source venv/bin/activate
# 解压
cd /data/soft
tar xf Django-1.10.7.tar.gz
# 查看
cd Django-1.10.7
cat INSTALL or README
# 安装
python setup.py install

拓展知识点:

python类型软件的安装流程
普通:
	解压  安装
特殊:
	解压  编译  安装
	编译:python setup.py build

2. django 项目创建

cd /data/server
django-admin startproject kungs

3. django 应用操作

​ 1) 创建应用

cd /data/server/kungs
python manage.py startapp test1

​ 2) 注册应用

# vimitcast/settings.py
INSTALL_APP= [
    ...
    'test1',
]

4. view 和 url 配置

  1. 需求:
访问django的页面请求为:127.0.0.1:8000/hello/,页面返回效果为:itcast v1.0
  1. 分析:
views文件定制逻辑流程函数
urls文件定制路由跳转功能 
  1. view配置文件生效
admin-1@ubuntu:/data/soft#cat /data/server/kungs/test1/views.py
from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.
def hello(resquest):
  return HttpResponse("kungs V1.0")
  1. url文件配置
admin-1@ubuntu:/data/soft#cat /data/server/kungs/kungs/urls.py
...
from django.contrib import admin
from test1.views import *
urlpatterns= [
	url(r'^admin/', admin.site.urls),
	url(r'^hello/$', hello),
]
  1. 启动django:
cd /data/server/kungs
python manage.py runserver  

注意:避免在运行的时候不能做别的时候,改为这样操作
(venv) root@instance-nl5v4j4n:/data/server/kungs# python manage.py runserver >dev/null 2>&1 &
[1] 10620
(venv) root@instance-nl5v4j4n:/data/server/kungs# 

# 解决8000端口被占用(Error: That port is already in use).
sudo fuser -k 8000/tcp

6.3.3 nginx环境

1. pcre 软件安装

# 解压
cd /data/soft/
tarxf pcre-8.39.tar.gz
# 查看帮助
cd pcre-8.39
INSTALL或者 README
# 配置
./configure
# 编译
make
# 安装
make install

拓展知识点:

linux中软件安装的一般流程

# 解压(解压文件,获取真正的配置文件)
tar
# 配置(根据默认的配置项或者更改配置项,生成编译配置文件(Makefile))
configure
# 编译(根据 Makefile 内容,编译生成指定的软件所需要的所有文件)
make
# 安装(将编译生成的所有文件,转移到软件指定安装的目录下面--prefix)
make install

2. nginx 软件安装

# 解压
cd /data/soft/
tar xf nginx-1.10.2.tar.gz
# 配置
(venv) root@instance-nl5v4j4n:/data/soft/nginx-1.10.2# cd nginx-1.10.2/
(venv) root@instance-nl5v4j4n:/data/soft/nginx-1.10.2# ./configure --prefix=/data/server/nginx
(venv) root@instance-nl5v4j4n:/data/soft/nginx-1.10.2# ./configure --prefix=/data/server/nginx --without-http_gzip_module
# 编译
make
# 安装
make install

nginx 简单操作

# 检查
/data/server/nginx/sbin/nginx -t
# 开启
/data/server/nginx/sbin/nginx
# 关闭
/data/server/nginx/sbin/nginx -s stop
# 重载
/data/server/nginx/sbin/nginx -s reload

# 查看端口,检查是否运行
netstat -tnulp

常见报错问题

突发问题:

(venv) root@instance-nl5v4j4n:/data/server/nginx#./sbin/nginx -t

./sbin/nginx:error while loading shared libraries: libpcre.so.1: cannot open shared objectfile: No such file or directory

分析:

1、先看报错
2、思考,是否报错真实有效
	分析: 谁错了
3、查找文件
	全名找不到,我们使用正则
4、找到文件,我没有问题
	nginx默认找库文件的路径有问题
5、解决

解决:

(venv) root@instance-nl5v4j4n:/data/soft/nginx-1.10.2#ldd /data/server/nginx/sbin/nginx 
linux-vdso.so.1 =>  (0x00007ffdb9154000)
libdl.so.2 =>/lib/x86_64-linux-gnu/libdl.so.2 (0x00007fa59379b000)
libpthread.so.0 =>/lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fa59357e000)
libcrypt.so.1 =>/lib/x86_64-linux-gnu/libcrypt.so.1 (0x00007fa593345000)
libpcre.so.1 => not found
libc.so.6 =>/lib/x86_64-linux-gnu/libc.so.6 (0x00007fa592f7c000)
/lib64/ld-linux-x86-64.so.2(0x0000564bfef41000)

查找文件:

(venv) root@instance-nl5v4j4n:/data/soft/nginx-1.10.2#find / -name "libpcre.so.1"
/data/soft/pcre-8.39/.libs/libpcre.so.1
/usr/local/lib/libpcre.so.1
...

链接该文件

(venv) root@instance-nl5v4j4n:/data/soft/nginx-1.10.2#ln -s /usr/local/lib/libpcre.so.1 /lib/x86_64-linux-gnu/

再次检查一下nginx的配置文件

(venv) root@instance-nl5v4j4n:/data/soft/nginx-1.10.2#/data/server/nginx/sbin/nginx -t

nginx:the configuration file /data/server/nginx/conf/nginx.conf syntax is ok

nginx:configuration file /data/server/nginx/conf/nginx.conf test is successful

---------------

6.3.4 nginx代理django

nginx 配置简介

nginx的目录结构

root@instance-nl5v4j4n:/data/soft/nginx-1.10.2# tree -L 2 /data/server/nginx/
/data/server/nginx/
├── client_body_temp
├── conf
│   ├── fastcgi.conf
│   ├── fastcgi.conf.default
│   ├── fastcgi_params
│   ├── fastcgi_params.default
│   ├── koi-utf
│   ├── koi-win
│   ├── mime.types
│   ├── mime.types.default
│   ├── nginx.conf
│   ├── nginx.conf.default
│   ├── scgi_params
│   ├── scgi_params.default
│   ├── uwsgi_params
│   ├── uwsgi_params.default
│   └── win-utf
├── fastcgi_temp
├── html
│   ├── 50x.html
│   └── index.html
├── logs
│   ├── access.log
│   ├── error.log
│   └── nginx.pid
├── proxy_temp
├── sbin
│   └── nginx
├── scgi_temp
└── uwsgi_temp

9 directories, 21 files

nginx 配置文件介绍

全局配置段                  

http配置段

server配置段           项目或者应用

 location配置段. url配置

nginx 代理配置

案例需求:

​ 访问地址 182.61.28.143/hello/ 跳转到 127.0.0.1:8000/hello/的django服务来处理hello请求

在这里插入图片描述

编辑配置文件实现代理功能

配置内容

62:	location /hello/ {
63:		proxy_pass http://127.0.0.1:8000;
64:	}

注释:当我访问地址是

配置文件生效

/data/server/nginx/sbin/nginx -t
/data/server/nginx/sbin/nginx -s reload

第7章 手工代码发布

7.1 方案分析

发布需求:

​ 手工方式部署代码

在这里插入图片描述

发布方案:

  1. 获取代码
sed -i 's#文件原始的内容#替换后的内容#g' 要更改到文件名

打包代码

在这里插入图片描述

  1. 传输代码

在这里插入图片描述

  1. 关闭应用

  2. 解压代码

  3. 放置代码​

  4. 备份老文件

在这里插入图片描述

  1. 放置新文件

在这里插入图片描述

  1. 开启应用

  2. 检查

注意:

​ 获取代码和打包代码在==代码仓库主机==上进行操作

​ 其他操作,都在**线上服务器**进行操作

--------------------

7.2 方案实施

1. 获取代码

mkdir /data/codes -p
cd /data/codes
sed -i 's#1.0#1.1#' django/views.py 
sed -i	's#原内容#替换后内容#g' 文件

2. 打包代码

cd /data/codes/
tar zcf django.tar.gz django

3. 传输代码

cd /data/codes/
scp django.tar.gz [email protected]:/data/codes/ 

注意:前面两步在代码仓库主机上NgandeMBP:~ kungs$操作

4. 关闭应用

1. 关闭nginx应用
	/data/server/nginx/sbin/nginx -s stop
2. 关闭django应用
	根据端口查看进程号,
		lsof -Pti :8000
	杀死进程号
		kill 56502
	一条命令搞定它:
		kill $(lsof -Pti:8000)

5. 解压代码

cd /data/codes
tar xf django.tar.gz

6. 放置代码

1. 备份老文件
    需求:备份的格式:
        文件名-时间戳
            时间戳:年月日时分秒
                date +%Y%m%d%H%M%S
        mv /data/server/kungs/test1/views.py /data/backup/views.py-$(date +%Y%m%d%H%M%S)
2. 放置新文件
    cd /data/codes
    mv django/views.py /data/server/kungs/test1/

7. 开启应用

开启django应用
    source /data/virtual/venv/bin/activate
    cd /data/server/kungs
    python manage.py runserver >> /dev/null 2>&1 &
    deactivate
开启nginx应用
	/data/server/nginx/sbin/nginx

8. 检查

netstat -tnulp | grep ':80'

完整的代码:

#!/bin/bash
# 功能:打包代码	
# 脚本名:deploy.sh	
# 作者:kungs
# 版本:V 0.2	
# 联系方式:[email protected]

# 获取代码
get_code(){
  echo "获取代码"
}
# 打包代码
tar_code(){
  echo "打包代码"
  ssh [email protected] "/bin/bash /data/scripts/tar_code.sh"
}
# 传输代码
scp_code(){
  echo "传输代码"
  cd /data/codes
  # [ -f django.tar.gz ] && rm -f django.tar.gz
  scp [email protected]:/data/codes/django.tar.gz ./
}
# 关闭应用
stop_serv(){
  echo "关闭应用"
  echo "关闭nginx应用"
  /data/server/nginx/sbin/nginx -s stop
  echo "关闭django应用"
  kill $(lsof -Pti:8000)
}
# 解压代码
untar_code(){
  echo "解压代码"
  cd /data/codes
  tar xf django.tar.gz
}
# 放置代码
fangzhi_code(){
  echo "放置代码"
  echo "备份老文件"
  mv /data/server/kungs/test1/views.py /data/backup/views.py-$(date +%Y%m%d%H%M%S)
  echo "放置新文件"
  # mv /data/codes/django/views.py /data/server/kungs/test1/
  cp /data/codes/django/views.py /data/server/kungs/test1/
}
# 开启应用
start_serv(){
  echo "开启应用"
  echo "开启django应用"
  source /data/virtual/venv/bin/activate
  cd /data/server/kungs/
  python manage.py runserver >> /dev/null 2>&1 &
  deactivate
  echo "开启nginx应用"
  /data/server/nginx/sbin/nginx
}
# 检查
check(){
  echo "检查应用"
  netstat -tnulp | grep ':80'
}
# 部署函数
pro_deploy(){
  get_code
  tar_code
  scp_code
  stop_serv
  untar_code
  fanghi_code
  start_serv
  check
}
# 主函数
main(){
  pro_deploy
}
# 调用主函数
main

--------------------

注: 大型脚本之[命令填充](#_8.2.2 命令填充)


第8章 脚本发布代码

代码部署流程拆分成两部分:

  1. 简单脚本(远端主机上执行)

  2. 大型脚本(线上机器执行)

8.1 简单脚本编写

1、命令罗列实现功能
2、固定内容变量实现
3、功能函数实现
4、远程执行命令

8.1.1 命令罗列

目的:实现代码仓库主机上的操作命令功能即可

实现简单的功能— 简单的命令罗列

#!/bin/bash
# 功能:打包代码
# 脚本名:tar_code.sh
# 作者:kungs
# 版本:V 0.1
# 联系方式:[email protected]

cd /data/codes
[ -f django.tar.gz ] && rm -f django.tar.gz
tar zcf django.tar.gz django

脚本编写完成后,进行测试:

sed -i 's#1.1#1.2#' /data/codes/django/views.py
bash /data/scripts/tar_code.sh

查看压缩文件内容

zcat django.tar.gz 

8.1.2 固定内容变量化

问题:脚本里面的手写的固定的内容太多了,更改时候费劲

脚本优化之 固定内容变量化

#!/bin/bash
# 功能:打包代码
# 脚本名:tar_code.sh
# 作者:kungs
# 版本:V 0.2
# 联系方式:[email protected]

FILE='django.tar.gz'
CODE_DIR='/data/codes'
CODE_PRO='django'

cd "${CODE_DIR}"
[ -f "$Misplaced &{FILE}" ] && rm -f "${FILE}"
tar zcf "${FILE}" "${CODE_PRO}"   

脚本编写完成后,进行测试:

sed -i 's#1.2#1.3#' /data/codes/django/views.py
bash /data/scripts/tar_code.sh

查看压缩文件内容

zcat django.tar.gz
# mac 下的方法:
gunzip -c django.tar.gz

8.1.3 功能函数化

需求:三条命令其实是一个组合,实现的是一个功能

脚本优化之 功能函数化

#!/bin/bash
# 功能:打包代码
# 脚本名:tar_code.sh
# 作者:kungs
# 版本:V 0.3
# 联系方式:[email protected]

FILE='django.tar.gz'
CODE_DIR='/data/codes'
CODE_PRO='django'

code_tar(){
	cd "${CODE_DIR}"
	[ -f "$Misplaced &{FILE}" ] && rm -f "${FILE}"
	tar zcf "${FILE}" "${CODE_PRO}"   
}
code_tar

脚本编写完成后,进行测试:

sed -i 's#1.2#1.3#' /data/codes/django/views.py
bash /data/scripts/tar_code.sh

查看压缩文件内容

zcat /data/codes/django.tar.gz 

8.1.4 远程执行

远程命令执行

格式:

ssh 远程主机登录用户名@远程主机ip地址 "执行命令"

效果

NgandeMBP:scripts kungs$# ssh [email protected] "ifconfig eth0"
eth0      Link encap:Ethernet  HWaddr 00:0c:29:f7:ca:d4  
			inet addr:182.61.28.143  Bcast:182.168.56.255  Mask:255.255.255.0
			...

远程执行脚本测试

1. 远程更新文件内容
ssh [email protected] "sed -i /'s#1.4#1.5#' /data/codes/django/views.py"
2. 远程查看脚本
ssh [email protected] "ls /data/scripts"
3. 远程执行脚本
ssh [email protected] "/bin/bash /data/scripts/tar_code.sh"
4. 远程检查更新效果
ssh [email protected] "zcat /data/codes/django.tar.gz"

--------------------

8.2 大型脚本编写

本地是指线上服务器主机(云服务器)

​ 我们先来回顾一下代码[发布流程图](#_5.2.1 流程简介)

编写大型脚本有一个流程:

一、脚本框架
二、[命令填充](#_7.2 方案实施)
三、完善功能
    增加日志功能
    增加锁文件功能
    增加主函数逻辑
    增加参数安全措施

8.2.1 脚本框架

不用脚本框架:1、命令多; 2、功能多; 3、不好组合

需求:先将脚本所涉及的所有业务流程跑通

方案:使用函数来体现

脚本实施:

#!/bin/bash
# 功能:打包代码	
# 脚本名:deploy.sh	
# 作者:kungs
# 版本:V 0.1	
# 联系方式:[email protected]

# 获取代码
get_code(){
  echo "获取代码"
}

# 打包代码
tar_code(){
  echo "打包代码"
}

# 传输代码
scp_code(){
echo "传输代码"
}

# 关闭应用
stop_serv(){
  echo "关闭应用"
  echo "关闭nginx应用"
  echo "关闭django应用"
}

# 解压代码
untar_code(){
  echo "解压代码"
}

# 放置代码
fangzhi_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
  fangzhi_code
  start_serv
  check
}

# 主函数
main(){
  deploy_pro
}

# 执行主函数
main

8.2.2 命令填充

需求:在流程跑通的情况下,执行完整的代码部署过程

方案:在脚本框架中,填写执行成功的命令

脚本实施:

#!/bin/bash
# 功能:打包代码	
# 脚本名:deploy.sh	
# 作者:kungs	
# 版本:V 0.2	
# 联系方式:[email protected]

# 获取代码
get_code(){
  echo "获取代码"
}

# 打包代码
tar_code(){
  echo "打包代码"
  ssh [email protected] "/bin/bash /data/scripts/tar_code.sh"
}

# 传输代码
scp_code(){
  echo "传输代码"
  cd /data/codes
  [ -f django.tar.gz ] && rm -f django.tar.gz
  scp [email protected]:/data/codes/django.tar.gz ./
}

# 关闭应用
stop_serv(){
  echo "关闭应用"
  echo "关闭nginx应用"
  /data/server/nginx/sbin/nginx -s stop
  echo "关闭django应用"
  kill $(lsof -Pti :8000)
}

# 解压代码
untar_code(){
  echo "解压代码"
  cd /data/codes
  tar xf django.tar.gz
}

# 放置代码
fangzhi_code(){
  echo "放置代码"
  echo "备份老文件"
  mv /data/server/kungs/test1/views.py /data/backup/views.py-$(date +%Y%m%d%H%M%S)
  echo "放置新文件"
  mv /data/codes/django/views.py /data/server/kungs/test1/
}

# 开启应用
start_serv(){
  echo "开启应用"
  echo "开启django应用"
  source /data/virtual/venv/bin/activate
  cd /data/server/kungs/
  python manage.py runserver >> /dev/null 2>&1 &
  deactivate
  echo "开启nginx应用"
  /data/server/nginx/sbin/nginx
}
# 检查
check(){
  echo "检查项目"
  netstat -tnulp | grep ':80'
}

...

8.2.3 增加日志功能

需求:1、追踪记录; 2、数据说话

方案:增加日志功能

1、日志文件
	/data/logs/deploy.log
2、日志格式
	日期 时间 脚本名称 步骤

知识点:

文件内容追加: >>
    日期:date +%F
    时间:date +%T
    脚本:$0

脚本实施:

#!/bin/bash
...

# 定义本地变量
LOG_FILE='/data/logs/deploy.log'
# 增加日志功能函数
write_log(){
  DATE=$(date +%F)
  TIME=$(date +%T)
  buzhou="$1"
  echo "${DATE} ${TIME} $0 : ${buzhou}" >> "${LOG_FILE}"
}

# 获取代码
get_code(){
  ...
  write_log "获取代码"
}

# 打包代码
tar_code(){
  ...
  write_log "打包代码"
}

# 传输代码
scp_code(){
  ...
  write_log "传输代码"
}

# 关闭应用
stop_serv(){
  ...
  write_log "关闭应用"
  ...
  write_log "关闭nginx应用"
  ...
  write_log "关闭django应用"
}

# 解压代码
untar_code(){
  ...
  write_log "解压代码"
}

# 放置代码
fangzhi_code(){
  ...
  write_log "放置代码"
  ...
  write_log "备份老文件"
  ...
  write_log "放置新文件"
}

# 开启应用
start_serv(){
  ...
  write_log "开启应用"
  ...
  write_log "开启django应用"
  ...
  write_log "开启nginx应用"
}
# 检查
check(){
  ...
  write_log "检查项目"
}

...

8.2.4 增加锁文件功能

需求:

同一时间段内,只允许有一个用户来执行这个脚本
如果脚本执行的时候,有人在执行,那么输出报错:
	脚本 deploy.sh 正在运行,请稍候...

设计:

1、锁文件       /tmp/deploy.pid
2、存在锁文件时候,输出报错信息
3、脚本执行的时候,需要创建锁文件
4、脚本执行结束的时候,需要删除锁文件

知识点:

条件和结果: 双分支if语句
文件表达式: -f  file_name
验证表达式: [ 表达式 ]
创建命令:touch
删除命令:rm -f

脚本实施:

#!/bin/bash
...
PID_FILE='/tmp/deploy.pid'
...
# 增加锁文件功能
add_lock(){
  echo "增加锁文件"
  touch "${PID_FILE}"
  write_log "增加锁文件"
}

# 删除锁文件功能
del_lock(){
  echo "删除锁文件"
  rm -f "${PID_FILE}"
  write_log "删除锁文件"
}

# 部署函数
deploy_pro(){
  add_lock
  ...
  del_lock
}

# 脚本报错信息
err_msg(){
  echo "脚本 $0 正在运行,请稍候..."
}

# 主函数
main(){
if [ -f "${PID_FILE}" ]
then
      err_msg
else
      deploy_pro
fi
}

# 执行主函数
main

8.2.5 脚本流程知识点填充

需求:

如果我给脚本输入的参数是deploy,那么脚本才执行,否则的话,提示该脚本的使用帮助信息,然后退出

提示信息:脚本 deploy.sh 的使用方式: deploy.sh [ deploy ]

分析:

1、脚本传参,就需要在脚本内部进行调用参数
2、脚本的帮助信息
3、脚本内容就需要对传参的内容进行判断 

知识点:

1、shell内置变量:$n
2、帮助信息: 简单函数定义和调用
3、内容判断: 多if语句或者case语句 

方案:

1、脚本的传参
    脚本执行:bash deploy.sh deploy
    位置参数的调用: $1
2、脚本的帮助信息
    定义一个usage函数,然后调用。
    提示信息格式:
    脚本 deploy.sh 的使用方式: deploy.sh [ deploy ]
3、内容判断
    main函数体调用函数传参: $1
    在main函数中,结合case语句,对传入的参数进行匹配
    如果传入参数内容是"deploy",那么就执行代码部署流程
    如果传入参数内容不是"deploy",那么输出脚本的帮助信息
    if语句和case语句的结合
        if语句在外,case语句在内
        case语句在外,if语句在内

脚本实施:

#!/bin/bash
...

# 脚本帮助信息
usage(){
  echo "脚本 $0 的使用方式: $0 [deploy]"
  exit
}

# 主函数
main(){
  case "$1" in 
    "deploy")
      if [ -f "${PID_FILE}" ]
      then
         err_msg
      else
        deploy_pro
      fi
    ;;
    *)
      usage
    ;;
  esac
}

# 执行主函数
main $1

8.2.6 输入参数安全优化

需求:

对脚本传入的参数的数量进行判断,如果参数数量不对,提示脚本的使用方式,然后退出

分析:

1、脚本参数数量判断
2、条件判断
    数量对,那么执行主函数
    数量不对,那么调用脚本帮助信息

知识点:

1、脚本参数数量判断
	shell内置变量:  $#
	条件表达式:     [ $# -eq 1 ]
2、条件判断:
	双分支if语句    

方案:

1、双分支if语句 + main函数调用

脚本实施:

#!/bin/bash
...

# 执行主函数
if [ $# -eq 1 ] 
then
  main $1
else
  usage
fi

完整的脚本代码实例查看:

1、deploy.sh

root@instance-nl5v4j4n:/data/scripts# cat deploy.sh
#!/bin/bash
# 功能:打包代码	
# 脚本名:deploy.sh	
# 作者:kungs
# 版本:V 0.6
# 联系方式:[email protected]

# 定义本地变量
LOG_FILE='/data/logs/deploy.log'
PID_FILE='/temp/deploy.pid'

# 增加日志功能函数
write_log(){
  DATE=$(date +%F)
  TIME=$(date +%T)
  buzhou="$1"
  echo "${DATE} ${TIME} $0 : ${buzhou}" >> "${LOG_FILE}"
}

# 增加锁文件
add_lock(){
  echo "增加锁文件"
  touch "${PID_FILE}"
  write_log "增加锁文件"
}
# 删除锁文件
del_lock(){
  echo "删除锁文件"
  rm -f "${PID_FILE}"
  write_log "删除锁文件"
}
# 获取代码
get_code(){
  echo "获取代码"
  write_log "获取代码"
}
# 打包代码
tar_code(){
  echo "打包代码"
  ssh [email protected] "/bin/bash /data/scripts/tar_code.sh"
  write_log "打包代码"
}
# 传输代码
scp_code(){
  echo "传输代码"
  cd /data/codes
  # [ -f django.tar.gz ] && rm -f django.tar.gz
  scp [email protected]:/data/codes/django.tar.gz ./
  write_log "传输代码"
}
# 关闭应用
stop_serv(){
  echo "关闭应用"
  write_log "关闭应用"
  echo "关闭nginx应用"
  /data/server/nginx/sbin/nginx -s stop
  write_log "关闭nginx应用"
  echo "关闭django应用"
  kill $(lsof -Pti:8000)
  write_log "关闭django应用"
}
# 解压代码
untar_code(){
  echo "解压代码"
  cd /data/codes
  tar xf django.tar.gz
  write_log "解压代码"
}
# 放置代码
putdemo_code(){
  echo "放置代码"
  write_log "放置代码"
  echo "备份老文件"
  mv /data/server/kungs/test1/views.py /data/backup/views.py-$(date +%Y%m%d%H%M%S)
  write_log "备份老文件"
  echo "放置新文件"
  # mv /data/codes/django/views.py /data/server/kungs/test1/
  cp /data/codes/django/views.py /data/server/kungs/test1/
  write_log "放置新文件"
}
# 开启应用
start_serv(){
  echo "开启应用"
  write_log "开启应用"
  echo "开启django应用"
  source /data/virtual/venv/bin/activate
  cd /data/server/kungs/
  python manage.py runserver >> /dev/null 2>&1 &
  deactivate
  write_log "开启django应用"
  echo "开启nginx应用"
  /data/server/nginx/sbin/nginx
  write_log "开启nginx应用"
}
# 检查
check(){
  echo "检查应用"
  netstat -tnulp | grep ':80'
  write_log "检查应用"
}
# 部署函数
pro_deploy(){
  add_lock
  get_code
  tar_code
  scp_code
  stop_serv
  untar_code
  putdemo_code
  start_serv
  check
  del_lock
}

# 报错信息
err_msg(){
  echo "该脚本 $0 正在运行,请稍候..."
}

# 帮助信息
usage(){
  echo "脚本 $0 的使用方式是:$0 [deploy]"
}

# 主函数
main(){
  case "$1" in
    deploy)
      if [ -f "${PID_FILE}" ]
      then
        err_msg
      else
        pro_deploy
      fi
      ;;
    *)
      usage
      ;;
  esac
}
# 调用主函数
if [ "$#" -ne 1 ]
then
  usage
else
  main $1
fi

2、tar_code.sh

root@instance-nl5v4j4n:/data/scripts# cat tar_code.sh

# !/bin/bash

# 功能:打包代码

# 脚本名:tar_code.sh

# 作者:kungs

# 版本:V 0.3

# 联系方式:[email protected]

# 定义本地变量

FILE='django.tar.gz'
CODE_DIR='/data/codes'
PRO_DIR='django'

# 定义一个功能函数

tar_code(){
    cd "${CODE_DIR}"
    [ -f "${FILE}" ] && rm -f "${FILE}"
    tar zcf "${FILE}" "${PRO_DIR}"
}

# 调用主函数

tar_code

--------------------

8.3 脚本调试功能

脚本调试的时候,主要分三种方式:

-n      检查脚本中的语法错误
-v      先显示脚本所有内容,然后执行脚本,结果输出,如果执行遇到错误,将错误输出。
-x      将执行的每一条命令和执行结果都打印出来

--------------------

8.4 生产脚本编写总结

8.4.1 简单脚本编写总结

1、手工执行的命令一定要可执行
2、命令简单罗列
3、固定的内容变量化
4、功能函数化

8.4.2 复杂脚本编写总结

1、手工执行的命令一定要可执行
2、根据发布流程编写脚本的框架
3、将手工执行的命令填充到对应的框架函数内部
4、增加日志功能,方便跟踪脚本历史执行记录
5、主函数中逻辑流程控制好
6、设计安全的方面:
    增加锁文件,保证代码发布的过程中不受干扰,
    输入参数数量
    输入参数匹配
    脚本帮助信息
7、调试脚本

8.4.3 注意事项:

1、命令一定要保证能正常执行
2、成对的符号,要成对写,避免丢失
3、函数调用,写好函数后,一定要在主函数中进行调用
4、避免符号出现中文
5、命令变量的写法一定要规范
6、固定的内容一定要变量实现,方便以后更改
7、日志的输出
8、脚本的传参和函数的传参要区别对待

备注:

文件整理:Kungs

博客:https://blog.csdn.net/yanpenggong

猜你喜欢

转载自blog.csdn.net/yanpenggong/article/details/83755800