查看shell编程帮助手册 man test
01.为什么学习shell脚本,脚本的用途
我们为什么学习shell脚本?
Shell可实现的功能
- 不管手动安装操作系统, 还是使用 Kickstart/Cobbler 自动化安装操作系统,系统底层的功能都是使用shell脚本实现的
- 使用shell脚本初始化操作系统,优化SSH、修改默认端口禁止root登陆、使用普通登陆提权方式、DNS解析、关闭SElinux 、设置防火墙允许的规则或端口、调整文件描述符、时间同步、字符集调整、安装常用软件、命令行安全等。
- 安装服务: 使用Shell脚本根据服务不同的版本号进行安装, 统计开发常用的版本号,写成脚本
配置服务: 使用shell脚本进行修改. - 启动服务的脚本 C6/C7 /etc/init.d/network Nginx启动脚本,停止程序,自发开发的程序会写启动脚本
比如启动一个py文件:
nohup python3.5 test.py --mysql-ip 10.0.0.51 --redis-ip 10.0.0.52 --port 6379 &
停止py程序:
ps 查找py进程 然后KILL掉 - Shell脚本进行代码上线.
开发写代码,写完代码给运维,运维进行打包,备份源码,放到站点目录解压,把这过程写入shell脚本进行自动化代码上线.
现在代码上线:Git+Jenkins+Shell脚本进行代码发布.
从开发修改-页面发布-用户可以浏览-代码上线. - 监控 Zabbix Cacti网卡流程 Nagios监控硬件交换机路由器
取值 --- 测试 -- 加入zabbix中
(使用Shell脚本进行取值)
硬件 服务监控 端口监控 连接状态监控 流量监控 日志监控等 - 日志分析 ELK日志展示 Shell脚本进行日志统计分析 AWK sed Grep等
日志切割 1.MV 2.重载服务
02.学习shell脚本用到的基础知识
- 熟练掌握VIM编辑器
- 熟悉SSH终端 Xshell CRT
- 熟练掌握Linux基础命令,因为命令的集合就是脚本
- 熟练掌握Linux正则表示式及AWK sed Grep
03.如何学习shell脚本
- Shell包含的内容: 变量基础 条件表达式 if判断 For循环 While循环 Utile循环 Case语句 循环过程中控制指令 Continue Break Exit 数组
- 能看懂别人写的代码,掌握常见的各种语法,练习-重复编写Shell脚本
从简单的变量 判断循环开始
阅读-模仿 重复 分析 总结-->文档 - 要有编程思维
- 找一本合适的教材(老男孩Shell脚本 项目最多) 较全面的笔记
大忌: 不可拿来主意 可以模仿 一定要吃透 看懂 ->提升编程水平
学完Shell可以解决企业大部分脚本问题
4书写shell脚本规范
- 脚本存放固定的目录 mkdir /server/scripts -p 为了方便统一管理
- 开头需要加脚本的解释器 #!/bin/sh 指定解释器
- 附带作者及版本信息 对当前版本的说明
#作者 Author lzy
#时间 Crete time 20201010
#事件 cut log backup
#联系方式 QQ 110
#版本 Version v1.0 - 脚本扩展名使用.sh结尾
- 注释尽量不使用中文
- 成对的符号和循环格式一次性书写完毕
05.shell脚本执行的三组方式
- 使用bash执行脚本,在子shell中执行
sh test.sh
./test.sh - 使用source和.执行,在父shell中执行
. test.sh
source test.sh - 其它方式
cat test.sh | bash
bash < test.sh
06.变量的分类
- 环境变量(全局变量)
- 普通变量(局部变量)
07.变量的生命周期划分
- 永久的: 需要修改环境变量配置文件,变量永久生效 /etc/profile
- 临时的: 直接使用export声明变量即可,关闭shell则变量失效
08.变量名字的定义
-
变量名的要求: 字母、数字、下划线的组成,尽量以字母开头,见名知其意,等号两遍不允许有空格。
-
变量名=变量值
-
获取值变量的值: $变量名
-
系统环境都是大写字母
-
查看系统的环境变量env
-
oldboy_age 全小写
-
Oldboy_Age 大驼峰语法 首字母大写
-
oldboy_Age 小驼峰语法
-
OLDBOY_AGE 全大写
09.值的定义 数字 字符串
- 数字变量内容定义, 必须为连续的数字
oldboy_age=18 - 字符串的定义方式, 默认是双引号 混合字符串必须加双引号 数字 字符串 变量
oldboy='I am oldboy teacher' - 单引号和双引号的区别
- 单引号: 所见即所得 吃什么吐什么 定义的什么值输出或者调用的就是什么值 不会解析变量
- 双引号:可以解析变量
10.定义变量加export和不加的区别
- 不加export: 则只对当前的shell生效
- 加 export: 则对当前打开窗口所有的shell生效
11.shell特殊变量
$0 - 获取当前Shell脚本的文件名, 如果脚本全路径执行则显示全路径, basename 只获取脚本名称。
$n
- 获取当前脚本的第n个参数,n为0则是脚本名称,从$1开始代表脚本的第一个参数, $9以后需要加{} ${10}
$# - 获取shell脚本所有传参的总个数
$* 和 $$$@
获取shell脚本所有传参的参数,如果不加双引号则和$@相同,在循环语句中如果加上双引号,则表示将所有的参数视为单个字符串
$? - 获取执行上一条命令的执行状态结果,返回值0为成功 非0失败
$$
- 获取当前脚本的PID
echo $$ > /tmp/test_sh.pid
$! - 获取上一个后台工作脚本进行的PID
echo $!
$_ - 获取脚本最后的一个参数 类似于ESC .
12.传参的三种方法
1.直接传参
[root@shell scripts]# cat test.sh
#!/bin/bash
ping -c1 -W1 $1 &>/dev/null
[ $? -eq 0 ] && echo "ping $1 is ok" || echo "ping $1 is error"
[root@shell scripts]# sh test.sh www.baidu.com
ping www.baidu.com is ok
[root@shell scripts]# sh test.sh www.baiduuuu.com
ping www.baiduuuu.com is error
2.变量赋值
[root@shell scripts]# cat test.sh
#!/bin/bash
url=$1
ping -c1 -W1 $url &>/dev/null
[ $? -eq 0 ] && echo "ping $url is ok" || echo "ping $url is error"
[root@ldx ~]#sh test.sh
ping is error
[root@ldx ~]#sh test.sh www.baidu.com
ping www.baidu.com is ok
3.read读入
[root@shell scripts]# cat test.sh
#!/bin/bash
read -p "Please input url: " url
ping -c1 -W1 $url &>/dev/null
[ $? -eq 0 ] && echo "ping $url is ok" || echo "ping $url is error"
----------------
read -p "Please input name:" name
read -p "Please input age:" age
echo $name
echo $age
-----------------
read -p "Please input name and age: " name age
echo $name
echo $age
13.变量的切片和获取字符长度的操作
- 变量子串切片
- ${变量:n:m} - 从下标2开始,切m个字符
[root@ldx ~]#name='I am lidexian'
[root@ldx ~]#echo ${name:2:4}
am l
- 统计变量值字符串长度
- 统计字符串的方法
[root@ldx ~]#echo $name
I am lidexian
[root@ldx ~]#echo $name | wc -L
13
[root@ldx ~]#echo $name | awk '{print length}'
13
- 使用变量统计的方法 -- $
[root@ldx ~]#echo ${#name}
13
- 示例 -- 输出每个单词的长度
[root@ldx ~]#echo $name | xargs -n1 | awk '{print length}'
1
2
8
14.变量的删除和替换
- 变量删除 -- ${变量#*.}
- # 表示从行首开始删除
- * 删除任意字符
- . 删除到第一个点结束
[root@ldx ~]# url='www.sina.com.cn'
[root@ldx ~]# echo ${url#*.}
sina.com.cn
- ${变量#..} - 删除到第二个点结束
[root@ldx ~]#url='www.sina.com.cn'
[root@ldx ~]#echo ${url#*.*.}
com.cn
- ${变量##*.} - 2个#表示贪婪匹配,匹配到最后一个点
[root@ldx ~]#url='www.sina.com.cn'
[root@ldx ~]#echo ${url##*.}
cn
- ${url%.*}
- % 表示从行尾开始删
- * 删除任意字符
- . 删除到点结束
[root@ldx ~]#url='www.sina.com.cn'
[root@ldx ~]#echo ${url%.*}
www.sina.com
- ${url%%.*} - 贪婪匹配,匹配到第一个点结束
[root@ldx ~]#url='www.sina.com.cn'
[root@ldx ~]#echo ${url%%.*}
www
- 变量的替换
- ${变量/被替换内容/替换内容} - 替换第一个就结束
[root@ldx ~]#url='www.sina.com.cn'
[root@ldx ~]#echo ${url/w/a}
aww.sina.com.cn
- ${变量//被替换内容/替换内容} - 全局替换
[root@ldx ~]#url='www.sina.com.cn'
[root@ldx ~]#echo ${url//w/a}
aaa.sina.com.cn
15. 变量数值运算
- expr - 只能做整数运算
[root@ldx ~]#num1=3
[root@ldx ~]#num2=5
[root@ldx ~]#expr $num2 - $num1 + $num1 \* $num2 / $num1
7
- $(()) 双括号是运算,单括号是执行变量,只支持整数运算
[root@ldx ~]#num1=3
[root@ldx ~]#num2=5
[root@ldx ~]#echo $(($num2 - $num1 + $num1 * $num2 / $num1))
7
- $[] 只支持整数运算
[root@ldx ~]#num1=3
[root@ldx ~]#num2=5
[root@ldx ~]#echo $[$num2 - $num1 + $num1 * $num2 / $num1]
7
- let a++ 只支持整数运算
[root@ldx ~]#let a++
[root@ldx ~]#echo $a
1
[root@ldx ~]#let a++
[root@ldx ~]#echo $a
2
- bc - 支持小数运算
[root@ldx ~]#a=1.2
[root@ldx ~]#b=2.1
[root@ldx ~]#echo $a + $b | bc
3.3
16.shell条件判断语句
- 文件判断语句
- [ -e file|dir ] 文件或目录存在即为真
- [ -f file ] 文件存在即为真
- [ -d dir ] 目录存在即为真
- [ -r file ] 文件存在,且拥有读权限则为真
- [ -w file ] 文件存在,且拥有写的权限则为真
- [ -x file ] 文件存在,且拥有执行权限则为真
- 整数数值比较
表达式 | 描述 | 英文 |
---|---|---|
[ $num -eq 10 ] | 等于 | equal |
[ $num -ne 10 ] | 不等于 | not equal |
[ $num -ge 10 ] | 大于等于 | greater or equal |
[ $num -le 10 ] | 小于等于 | less or equal |
[ $num -gt 10 ] | 大于 | greater than |
[ $num -lt 10 ] | 小于 | less than |
注意 如果是在[[]] (()) 中的比较使用 = != > >= < <=
- 多条判断语句
- -a and 两端都要成立则为真
- -o or 一端成立则为真
[root@ldx ~]#[ 10 -eq 10 -a 3 -gt 5 ] && echo true || echo error
error
[root@ldx ~]#[ 10 -eq 10 -o 3 -gt 5 ] && echo true || echo error
true
16.字符串对比和正则比对
- 字符串对比
- [ str1 = str2 ] 等于
- [ str1 != str2 ] 不等于
- 正则比对 - 需要使用双中括号 [[]]
- [[字符串 =~ 正则]]
[root@ldx ~]#name='I am lidexian'
# 匹配与n结尾的字符串
[root@ldx ~]#[[ $name =~ n$ ]] && echo success || echo failed
success
# 匹配以i开头的字符串
[root@ldx ~]#[[ $name =~ ^i ]] && echo success || echo failed
failed
17. if判断语句
- fi - 表示判断语句结束
- 单分支判断
if [ $num -eq 10 ];then
# 成立则执行
echo "$num == 10"
fi
- 双分支判断
if [ $num -eq 10 ];then
# 成立则执行
echo "$num == 10"
else
# 否则执行
echo "$num != 10"
fi
- 多项分支
if [ $num -eq 10 ];then
# 成立则执行
echo "$num == 10"
elif [ $num -gt 10 ];then
# 判断条件成立,且上面的都不成立则执行
echo "$num > 10"
else
# 上面的都不成立执行
echo "$num != 10"
fi
18. case判断语法
-
- 等于0则执行
- ;; 表示结束
num=1
case $num in
0)
echo 000000
;;
1)
echo 111111
;;
*)
echo p、匹配任意字符
;;
19. 循环语句
break 跳出循环
continue 跳过当前一次循环
do 表示开始执行操作
done 表示循环语句结束
- for循环
[root@ldx scripts]#cat test.sh
#!/bin/bash
for i in 1 2 3
do
echo $i
done
[root@ldx scripts]#sh test.sh
1
2
3
- while循环
# 直接执行
while 判断条件
do
执行语句
done
# 逐行读取文本进行操作
while read line
do
echo $line
done < file
20. function 函数
- 定义方式
# 简写方式
func(){
echo $1
}
# 官方完整版
function func(){
echo $1
}
- 调用方式
function func(){
echo $1
}
# 调用
func
- 传参方式
# $1 为第一个参数,$2 第二个参数
function func(){
echo $1 $2
}
# 调用
func 10 20
# 调用结果
10 20
21. 多线程执行
- 用大括号包裹,在大括号后面加&
for i in `seq 100`
do
{
ping www.baidu.com &>/dev/null
if [ $? -eq 0 ];then
echo 'ping www.baidu.com ok'
else
echo 'ping www.baidu.com failed'
fi
}&
done
22. wait 等待
- 会等待wait上面的程序全部执行完成,才会执行下面的
for i in `seq 100`
do
{
ping www.baidu.com &>/dev/null
if [ $? -eq 0 ];then
echo 'ping www.baidu.com ok'
else
echo 'ping www.baidu.com failed'
fi
}&
done
wait
echo 'ping 全部执行完成'
23. 数组
- unset array 取消数组定义
- 定义
- 数组的值写在小括号()里,元素以空格分割
array=(1 2 3)
array[4]=4
- 查看
# 查看全部值
echo ${array[*]}
# 查看数组所有下标
echo ${!array[*]}
# 查看数组长度
echo ${#array[*]}
# 查看单个值
echo ${array[1]}
- 关联数组定义
declare -A array
array=([a]=1 [b]=3)
array[c]=4