什么是shell
命令解释器,位于系统最外层,负责人机对话:命令的翻译输入和处理结果输出
什么是shell脚本
将系统命令放在一起,顺序执行,即系统命令堆积; 特定格式、特定语法、系统命令,共同组成的文件
shell脚本能做什么
基础配置:系统初始化操作、系统更新、内核调整、网络、时区
安装程序:部署LNMP、LAMP、LMT、mysql、nginx、Redis
配置变更:nginx conf、PHP conf、mysql conf、Redis conf
业务部署:shell配合git、jenkins实现自动化部署以及回滚
日常备份:使用shell脚本对mysql进行全备和增备
信息采集:zabbix+shell,硬件、系统、服务、网络
日志分析:取值、排序、去重、统计、分析
服务扩容:监控脚本监控服务器集群cpu使用率,超出80%触发动作脚本 (调用api开通云主机,初始化、加集群)
服务缩容:监控脚本监控服务器集群cpu使用率,低于20%触发动作脚本 (查看节点数,判断预设值,释放节点)
总结:简化工作,避免重复性、周期性操作,减少故障几率
学习shell需要哪些知识
熟练vim辑编器 熟练Linux命令 熟练Linux三剑客grep sed awk 学习方法:基础命令、基础服务、大量练习、思路
shell基本规范
脚本存放在固定目录 开头#!/bin/bash,指定命令解释器 作者和版本 扩展名.sh,便于识别 复杂脚本,添加必要注释 成对符号一次书写完成 循环格式一次性输入完成 脚本中文件必须使用绝对路径
vim test1.sh #!/usr/bin/bash 脚本中不写,如果./执行,默认调用bash翻译 脚本中写了解释器,使用./执行直接调用相应解释器
shell脚本五种运行方式
- ./脚本名 相对路径方式运行必须有x权限
- sh 脚本名
- source 脚本名 以root身份运行可以没有x权限
- . 脚本名
- /sh/test.sh 绝对路径方式运行必须有x权限
shell变量
变量是shell传递数据的一种方法,即用一个固定的字符串去表示不固定的值,便于后期引用
变量命名规范
命名要求:字母、数字、下划线组成,字母开头(不能使用数字开头)
类型:字符类型(不能用于计算)、数值类型(可以计算)
符号:'' 单引号 "" 双引号 `` 反撇号
'' 表示字符串(不对变量进行解释)
"" 表示字符串(对变量进行取值操作)
`` 反撇号 表示将一个命令的执行结果赋值给一个变量(不能嵌套使用)
$() 表示将一个命令的执行结果赋值给一个变量(可以嵌套) 例:$($()) 可以使用
注意:所有符号必须是英文符号 () () '' ‘’
变量名尽量具备一定含义,但不要和系统命令冲突;等号赋值,两边不能空格
例1:
1. [root@daxia ~]# ip=192.168.8.100 #不要和已有的系统命令冲突 2. [root@daxia ~]# HostName_Ip=192.168.8.100 #推荐驼峰式命名
例2:
1. [root@daxia ~]# HostName=$(hostname) #定义hostname为HostName 2. [root@daxia ~]# echo $HostName #查看变量可以看到主机名
shell变量定义的方式
用户自定义变量:人为定义变量名称
系统环境变量:系统操作环境相关数据
位置参数变量:向脚本传递参数,名称固定,作用固定
预定义变量:bash定义好的变量,名称固定,作用固定
自定义变量
(1) 变量名不能出现"-"横杠(可以下划线),变量值有空格需要引号括起来
1. [root@daxia ~]# var="hello world" 2. [root@daxia ~]# echo $var 3. hello world
(2) 引用变量,$变量名 或 ${变量名}
1. [root@daxia ~]# echo $var #正常查看变量 2. hello world 3. [root@daxia ~]# echo $var_log #变量无法引用 4. 5. [root@daxia ~]# echo ${var}_log #变量可以引用 6. hello world_log
注意:在变量链接字符串时,需要将变量使用{}阔起
(3) 查看变量,set显示所有变量(自定义和环境变量)
[root@daxia ~]# set | grep var
(4) 取消变量,作用范围:当前shell
[root@daxia ~]# unset var
(5) 引用变量,"" 双引号属于弱引用,‘’单引号属于强引用
1. [root@daxia ~]# var="hello world" 2. [root@daxia ~]# echo "$var hello china" #需要引用变量值 3. hello world hello china 4. [root@daxia ~]# echo '$var hello china' #只想引用变量名,不执行$特殊符号 5. $var hello china 6. [root@daxia ~]# echo "$var hello china $SHELL" #部分变量执行,部分变量不执行 7. hello world hello china /bin/bash
(6) 变量命令赋值,使用反撇号或者$()
1. [root@daxia ~]# Ip=`ifconfig ens33 | grep 'inet' | grep -v inet6 | awk '{print $2}'` 2. [root@daxia ~]# Ip=$(ifconfig ens33 | grep 'inet' | grep -v inet6 | awk '{print $2}') 3. #两种方法都可以赋值,但区别是反撇号无法嵌套 4. [root@daxia ~]# echo $Ip 5. 192.168.8.1
系统环境变量
(1) 使用系统已定义好的变量
export
echo "宿主目录: $HOME"
echo "当前目录: $PWD"
echo "主机名: $HOSTNAME"
echo "客户端地址和端口: $SSH_CONNECTION"
环境变量配置文件:
/etc/profile (全局配置文件)
/root/.bash_profile (root用户的局部配置文件)
/home/test/.bash_profile (test用户的局部配置文件)
(2) 自定义环境变量
1. [root@daxia ~]# var1="hello beijing" #定义局部变量,子shell不识别 2. [root@daxia ~]# cat >> env.sh << END 3. > #!/bin/bash 4. > echo $var1 5. > END 6. [root@daxia ~]# sh env.sh 7. hello beijing 8. 9. [root@daxia ~]# export var1 #把局部变量发布到全局,子shell也识别
预定义变量
1. [root@daxia ~]# vim variable.sh 2. #!/bin/bash 3. echo "当前shell脚本的文件名:$0" 4. echo "第1个shell脚本位置参数:$1" 5. echo "第2个shell脚本位置参数:$2" 6. echo "第3个shell脚本位置参数:$3" 7. echo "第10个shell脚本位置参数:${10}" 8. echo "所有传递的位置参数:$*" 9. echo "所有传递的位置参数:$@" 10. echo "总共传递的参数数量:$#" 11. echo "当前程序运行的PID:$$" 12. echo "上一个命令执行的返回结果:$?" #0成功 非0都是失败
查看结果
1. [root@daxia ~]# sh variable.sh 11 22 33 44 55 66 77 88 99 100 2. 当前shell脚本的文件名:variable.sh 3. 第1个shell脚本位置参数:11 4. 第2个shell脚本位置参数:22 5. 第3个shell脚本位置参数:33 6. 第10个shell脚本位置参数:100 7. 所有传递的位置参数:11 22 33 44 55 66 77 88 99 100 8. 所有传递的位置参数:11 22 33 44 55 66 77 88 99 100 9. 总共传递的参数数量:10 10. 当前程序运行的PID:100488 11. 上一个命令执行的返回结果:0
$* 和 $@ 的区别:
不加引号两者结果相同;加引号,$*把参数作为整体,$@把参数作为分散个体(脚本里面写了function和for语句,这里不用过多纠结,后面会讲解)。
1. [root@daxia ~]# vim variable1.sh 2. #!/bin/bash 3. test() { 4. echo "未加引号,两者相同" 5. echo $* 6. echo $@ 7. 8. echo "添加引号,两者对比" 9. 10. echo "----"\$*----"" 11. for I in "$*" 12. do 13. echo $I 14. done 15. echo "----"\$@----"" 16. for I in "$@" 17. do 18. echo $I 19. done 20. } 21. test 11 22 33 44
查看结果
1. [root@daxia ~]# sh variable1.sh 2. 未加引号,两者相同 3. 11 22 33 44 4. 11 22 33 44 5. 添加引号,两者对比 6. ----$*---- 7. 11 22 33 44 8. ----$@---- 9. 11 10. 22 11. 33 12. 44
位置变量
位置变量是预定义变量的一部分,是定义脚本后的参数位置的。 $1 $2 $3 . . $9 ${10}
补充变量
将命令执行结果传给变量(命令替换)
例1:打印今年和明年的时间
1. [root@daxia ~]# echo "今年是 $(date +%Y) 年" 2. 今年是 2023 年 3. [root@daxia ~]# echo "明年是 $(($(date +%Y)+1)) 年" 4. 明年是 2024 年
例2:命令的嵌套使用
[root@daxia ~]# Back=$(tar zcf /backup/root.tar.gz $(find /root/ -name "*.txt"))
测试命令 test
数值测试
-eq 等于则为真
-ne 不等于则为真
-gt 大于则为真
-ge 大于等于则为真
-lt 小于则为真
-le 小于等于则为真
字符串测试
= 等于则为真
!= 不相等则为真
-z 字符串 字符串的长度为零则为真
-n 字符串 字符串的长度不为零则为真
文件测试
-e 文件名 如果文件存在则为真
-r 文件名 如果文件存在且可读则为真
-w 文件名 如果文件存在且可写则为真
-x 文件名 如果文件存在且可执行则为真
-s 文件名 如果文件存在且至少有一个字符则为真
-d 文件名 如果文件存在且为目录则为真
-f 文件名 如果文件存在且为普通文件则为真
-c 文件名 如果文件存在且为字符型特殊文件则为真
-b 文件名 如果文件存在且为块特殊文件则为真
shell变量赋值
除了自定义和环境变量,还可以使用read进行交互式传递变量 例1:使用交互式指定备份目录、备份目标目录
1. [root@daxia ~]# vim read1.sh 2. #!/bin/bash 3. read -p "请输入备份的目录:" Dir 4. read -p "请输入备份到哪个目录:" Bak 5. echo "你要备份的目录是:${Dir}" 6. echo "-----正在备份${Dir}-----" 7. tar zcf "/${Bak}/${Dir}.tar.gz" /${Dir} &> /dev/null 8. echo "-----备份${Dir}完成-----"
查看结果
1. [root@daxia ~]# sh read1.sh 2. 请输入备份的目录:root 3. 请输入备份到哪个目录:backup 4. 你要备份的目录是:root 5. -----正在备份root----- 6. -----备份root完成----- 7. [root@daxia ~]# ll /backup/ 8. 总用量 3112 9. -rw-r--r--. 1 root root 3182694 4月 8 11:29 root.tar.gz
例2:输入bak_dir2返回结果
1. [root@daxia ~]# vim read2.sh 2. #!/bin/bash 3. back_dir1=/backup 4. read -p "请输入你的备份目录:" back_dir2 5. echo $back_dir1 6. echo /$back_dir2
查看结果
1. [root@daxia ~]# sh read2.sh 2. 请输入你的备份目录:back 3. /backup 4. /back
例3-1:输入IP监测是否可以通信
1. [root@daxia ~]# vim read3.sh 2. #!/bin/bash 3. read -p "请输入需要检测的ip地址:" IP 4. ping -w1 -c1 $IP &> /dev/null 5. 6. if [ $? -eq 0 ];then 7. echo -e "\033[32m $IP 可以通信 \033[0m" 8. else 9. echo -e "\033[31m $IP 不可通信 \033[0m" 10. fi
查看结果
1. [root@daxia ~]# sh read3.sh 2. 请输入需要检测的ip地址:192.168.8.1 3. 192.168.8.1 可以通信 4. [root@daxia ~]# sh read3.sh 5. 请输入需要检测的ip地址:192.168.8.8 6. 192.168.8.8 不可通信
例3-2:查看1到254网址是否可以通信
1. [root@daxia ~]# vim read3-2.sh 2. #!/bin/bash 3. IP=192.168.8. 4. for i in {1..254} 5. do 6. ping -w 1 -c 1 ${IP}$i &> /dev/null 7. if [ $? -eq 0 ];then 8. echo -e "\033[32m ${IP}$i 可以通信 \033[0m" 9. else 10. echo -e "\033[31m ${IP}$i 不可通信 \033[0m" 11. fi 12. done
查看结果
1. [root@daxia ~]# sh read3-2.sh 2. 192.168.8.1 可以通信 3. 192.168.8.2 不可通信 4. 192.168.8.3 不可通信 5. #省略部分内容
例4:使用read修改主机名和ip
1. [root@daxia ~]# vim read4.sh 2. #!/bin/bash 3. read -p "请输入你想修改的主机名:" HostName 4. read -p "你确定要修改如下内容,[Y|N]:" RC 5. if [ $RC == "Y" ];then 6. hostnamectl set-hostname $HostName 7. bash 8. else 9. exit 10. fi
查看结果
1. [root@daxia ~]# sh read4.sh 2. 请输入你想修改的主机名:bj_z3 3. 你确定要修改如下内容,[Y|N]:Y 4. [root@bj_z3 ~]#
脚本题
在每月第一天备份并压缩/etc目录的所有内容,放到/backup,备份文件以时间戳命名。
1. 备份目录在哪,/backup
2. 备份目标是谁,/etc
3. 命令,tar
4. 时间戳命名,$(date +%F)
1. [root@bj_z3 ~]# vim backup.sh 2. #!/bin/bash 3. Back_dir=/backup 4. 5. if [ -d $Back_dir ];then 6. tar zcf $Back_dir/etc_$(date +%F).tar.gz /etc 7. else 8. mkdir /backup && tar zcf $Back_dir/etc_$(date +%F).tar.gz /etc 9. fi
执行计划任务
1. [root@bj_z3 ~]# crontab -e 2. 30 23 1 * * /bin/bash /sh/backup.sh