Shell语言

Bash脚本编程

Bash基本格式

  1. [root@aarch64 ~]# cat > hello.sh << EOF
  2. > #!/bin/bash
  3. > echo "Hello,World~"
  4. > EOF
  5. [root@aarch64 ~]# chmod u+x hello.sh
  6. [root@aarch64 ~]# ./hello.sh
  7. Hello,World~
  8. [root@aarch64 ~]# sh hello.sh
  9. Hello,World~

变量说明

变量介绍

  1. 系统变量(set):$HOME,$PWD,$SHELL,$USER
  2. 用户自定义变量

变量定义

  • 变量名称可以由字母、数字和下划线组成。不能以数字开头
  • 等号两侧不能有空格
  • 变量名称一般习惯为大写
  1. #!/bin/bash
  2. #案例1:定义变量A
  3. A=100
  4. #输出变量需要加上$
  5. echo A=$A
  6. echo "A=$A"
  7. #案例2:撤销变量A
  8. unset A
  9. echo "A=$A"
  10. #案例3:声明静态的变量B=2,不能unset
  11. readonly B=2
  12. echo "B=$B"
  13. #案例4:将指令返回的结果赋值给变量
  14. C=`date`
  15. echo "C=$C"
  16. #旧版写法
  17. D=$(cal)
  18. echo "D=$D"
  19. #新版写法
  1. [root@aarch64 ~]# chmod +x var.sh
  2. [root@aarch64 ~]# ./var.sh
  3. A=100
  4. A=100
  5. A=
  6. B=2
  7. C=Tue Apr 13 23:00:42 CST 2021
  8. D= April 2021
  9. Su Mo Tu We Th Fr Sa
  10. 1 2 3
  11. 4 5 6 7 8 9 10
  12. 11 12 13 14 15 16 17
  13. 18 19 20 21 22 23 24
  14. 25 26 27 28 29 30
  15. [root@aarch64 ~]#

设置环境变量

  1. [root@aarch64 ~]# echo >> /etc/profile \
  2. > export TOMCAT_HOME=/usr/local/tomcat
  3. [root@aarch64 ~]# source /etc/profile
  4. [root@aarch64 ~]# echo $TOMCAT_HOME
  5. /usr/local/tomcat

多行注释

  1. #这是单行注释
  2. :<<!
  3. 这是多行注释
  4. !

位置参数

参数 说明
$n n为数字,$0代表命令本身,Shell - 图1{10}
$* 命令行中的所有参数,$*看作整体
$@ 命令行中的所有参数,$@把参数区分对待
$# 统计所有参数的个数

参考实例
  1. [root@aarch64 ~]# cat myshell.sh
  2. #!/bin/bash
  3. echo "0=$0 1=$1 2=$2"
  4. echo "所有的参数=$*"
  5. echo "$@"
  6. echo "参数的个数=$#"
  7. [root@aarch64 ~]# chmod u+x myshell.sh
  8. [root@aarch64 ~]# ./myshell.sh 111 222 333
  9. 0=./myshell.sh 1=111 2=222
  10. 所有的参数=111 222 333
  11. 111 222 333
  12. 参数的个数=3

预定义变量

参数 说明
$$ 当前进程的进程号
$! 后台运行的最后一个进程的进程号
$? 最后一次执行命令的返回状态,值为0表示成功,值为1表示失败

参考实例
  1. [root@aarch64 ~]# vim prevar.sh
  2. [root@aarch64 ~]# cat prevar.sh
  3. #!/bin/bash
  4. echo "当前执行的进程id=$$"
  5. #以后台的方式运行一个脚本,并获取他的进程号
  6. /root/myshell.sh &
  7. echo "最后一个后台方式允许的进程id=$!"
  8. echo "执行的结果是=$?"
  9. [root@aarch64 ~]# chmod u+x prevar.sh
  10. [root@aarch64 ~]# ./prevar.sh
  11. 当前执行的进程id=399
  12. 最后一个后台方式允许的进程id=400
  13. 执行的结果是=0
  14. [root@aarch64 ~]# 0=/root/myshell.sh 1= 2=
  15. 所有的参数=
  16. 参数的个数=0

运算符

  1. [root@aarch64 ~]# vim oper.sh
  2. [root@aarch64 ~]# cat oper.sh
  3. #!/bin/bash
  4. #案例1:计算(2+3)×4的值
  5. #使用第一种方式
  6. RES1=$(((2+3)*4))
  7. echo "res1=$RES1"
  8. #使用第二种方式(推荐使用)
  9. RES2=$[(2+3)*4]
  10. echo "res2=$RES2"
  11. #使用第三种方式,需注意
  12. #expr 1.反引号2.空格3.转义符4.临时变量
  13. TEMP=`expr 2 + 3`
  14. RES3=`expr $TEMP \* 4`
  15. echo "res3=$RES3"
  16. #案例2:请求出命令行的两个参数[整数]的和 20 50
  17. SUM=`expr $1 + $2`
  18. echo "sum=$SUM"
  19. [root@aarch64 ~]# chmod u+x ./oper.sh
  20. [root@aarch64 ~]# ./oper.sh 20 50
  21. res1=20
  22. res2=20
  23. res3=20
  24. sum=70

流程控制

条件判断

基本语法

  • [ condition ]

  • condition前后必须要有空格

  • 非空返回true,否则返回false

  • 0返回true,>1返回false
  1. #!/bin/bash
  2. if [ 条件判断式 ];then
  3. 程序
  4. fi
  1. #!/bin/bash
  2. if [ 条件判断式 ]
  3. then
  4. 程序
  5. elif [ 条件判断式 ]
  6. then
  7. 程序
  8. fi

常用判断条件
判断语句 说明
= 字符串比对
-lt 小于
-le 小于等于
-eq 等于
-gt 大于
-ge 大于等于
-ne 不等于
-r 有读的权限
-w 有写的权限
-x 有执行的权限
-f 文件存在且是常规文件
-e 文件存在
-d 文件存在且是一个目录

参考实例
  1. [root@aarch64 ~]# vim if.sh
  2. [root@aarch64 ~]# cat if.sh
  3. #!/bin/bash
  4. #案例1:"ok"是否等于"ok"
  5. #判断语句:使用 =
  6. if [ "ok" = "ok" ]
  7. then
  8. echo "equal"
  9. fi
  10. #案例2:23是否大于等于22
  11. #判断语句:使用 -ge
  12. if [ 23 -ge 22 ]
  13. then
  14. echo "大于"
  15. fi
  16. #案例3:/root/myshell.sh 目录中文件是否存在
  17. #判断语句:使用 -f
  18. if [ -f /root/myshell.sh ]
  19. then
  20. echo "存在"
  21. fi
  22. [root@aarch64 ~]# chmod u+x if.sh
  23. [root@aarch64 ~]# ./if.sh
  24. equal
  25. 大于
  26. 存在
  27. [root@aarch64 ~]# vim ifcase.sh
  28. [root@aarch64 ~]# cat ifcase.sh
  29. #!/bin/bash
  30. if [ $1 -ge 60 ]
  31. then
  32. echo "及格了"
  33. elif [ $1 -lt 60 ]
  34. then
  35. echo "不及格"
  36. fi
  37. [root@aarch64 ~]# chmod u+x ifcase.sh
  38. [root@aarch64 ~]# ./ifcase.sh 99
  39. 及格了
  40. [root@aarch64 ~]# ./ifcase.sh 59
  41. 不及格

case语句

语法结构
  1. case 变量 in
  2. "值1")
  3. 程序/代码
  4. ;;
  5. "值2")
  6. 程序/代码
  7. ;;
  8. esac

参考实例
  1. [root@aarch64 ~]# vim case.sh
  2. [root@aarch64 ~]# cat case.sh
  3. #!/bin/bash
  4. #案例1:当命令行参数是1时,输出“周一”
  5. #是2时,输出“周二”
  6. #输入其他时,输出“other...”
  7. case $1 in
  8. "1")
  9. echo "周一"
  10. ;;
  11. "2")
  12. echo "周二"
  13. ;;
  14. *)
  15. echo "other/^_^"
  16. esac
  17. [root@aarch64 ~]# chmod u+x case.sh
  18. [root@aarch64 ~]# ./case.sh 1
  19. 周一
  20. [root@aarch64 ~]# ./case.sh 2
  21. 周二
  22. [root@aarch64 ~]# ./case.sh 3
  23. other/^_^

for语句

语法结构
  1. #基本语法1
  2. for 变量 in 1 2 3
  3. do
  4. 程序/代码
  5. done
  6. #基本语法2
  7. for ((初始值;循环控制条件;变量变化))
  8. do
  9. 程序/代码
  10. done

参考实例
  1. #基本语法1案例
  2. [root@aarch64 ~]# vim for1.sh
  3. [root@aarch64 ~]# cat for1.sh
  4. #!/bin/bash
  5. #打印输入的参数,观察$*与$@的区别
  6. for i in "$*"
  7. do
  8. echo "输入的数是:$i"
  9. done
  10. #这是$@的表示方法
  11. echo "=========================="
  12. for j in "$@"
  13. do
  14. echo "输入的数分别为:$j"
  15. done
  16. [root@aarch64 ~]# chmod u+x for1.sh
  17. [root@aarch64 ~]# ./for1.sh 7890 7891 7893
  18. 输入的数是:7890 7891 7893
  19. ==========================
  20. 输入的数分别为:7890
  21. 输入的数分别为:7891
  22. 输入的数分别为:7893
  23. #基本语法2案例
  24. [root@aarch64 ~]# cat for2.sh
  25. #!/bin/bash
  26. #案例1:从1加到100的值输出显示
  27. SUM=0
  28. TMP=0
  29. for (( i=1; i<=100; i++))
  30. do
  31. SUM=$[$SUM+$i]
  32. TMP=`expr $TMP + $i`
  33. done
  34. echo "$SUM"
  35. echo "$TMP"
  36. [root@aarch64 ~]# ./for2.sh
  37. 5050
  38. 5050

while语句

基本语法
  1. while [ 条件判断式 ]
  2. do
  3. 程序/代码
  4. done

参考实例
  1. [root@aarch64 ~]# cat while.sh
  2. #!/bin/bash
  3. #案例1:从命令行输入一个数n,统计从1+...+n的值是多少?
  4. SUM=0
  5. i=0
  6. while [ $i -le $1 ]
  7. do
  8. SUM=$[$SUM+$i]
  9. i=$[$i+1]
  10. done
  11. echo "$SUM"
  12. [root@aarch64 ~]# ./while.sh 100
  13. 5050

read读取控制台输入

基本语法
选项 说明
-p 指定读取值时的提示符
-t 指定读取值时等待的时间(秒)

参考实例
  1. [root@aarch64 ~]# vim read.sh
  2. [root@aarch64 ~]# cat read.sh
  3. #!/bin/bash
  4. #案例1:读取控制台输入的NUM1的值
  5. read -p "请输入第一个数:" NUM1
  6. echo "你输入的数是:$NUM1"
  7. #案例2:读取控制台输入的NUM2的值,在10秒内输入
  8. read -t 10 -p "请输入第二个数:" NUM2
  9. echo "你输入的数是:$NUM2"
  10. [root@aarch64 ~]# chmod u+x read.sh
  11. [root@aarch64 ~]# ./read.sh
  12. 请输入第一个数:233
  13. 你输入的数是:233
  14. 请输入第二个数:11223
  15. 你输入的数是:11223

函数

系统函数
  1. #显示文件名
  2. [root@aarch64 ~]# basename /home/jsc/sdn.txt
  3. sdn.txt
  4. #显示文件名去掉.txt
  5. [root@aarch64 ~]# basename /home/jsc/sdn.txt .txt
  6. sdn
  7. #显示目录名
  8. [root@aarch64 ~]# dirname /home/jsc/sdn.txt
  9. /home/jsc

自定义函数
  1. [root@aarch64 ~]# vim fun.sh
  2. [root@aarch64 ~]# chmod u+x fun.sh
  3. [root@aarch64 ~]# ./fun.sh
  4. 请输入一个数n1=100
  5. 请输入一个数n2=200
  6. 和是=300
  7. [root@aarch64 ~]# cat fun.sh
  8. #!/bin/bash
  9. #案例1:计算输入的两个参数的和(动态获取),getSum
  10. #定义函数
  11. function getSum() {
  12. SUM=$[$n1+$n2]
  13. echo "和是=$SUM"
  14. }
  15. #输入两个值
  16. read -p "请输入一个数n1=" n1
  17. read -p "请输入一个数n2=" n2
  18. #调用自定义函数
  19. getSum $n1 $n2

Shell编程综合案例
  • 综合案例需求分析
  1. 每天凌晨2:30备份数据库study/data/backup/db
  2. 备份开始和备份结束能够给出相应的提示信息
  3. 备份后的文件要求以备份时间为文件名,并打包成.tar.gz的形式,比如:2021-03-12_230201.tar.gz
  4. 在备份的同时,检查是否有10天前备份的数据库文件,如果有就将其删除
  1. [root@aarch64 ~]# cd /usr/sbin/
  2. [root@aarch64 sbin]# vim mysql_db_backup.sh
  3. [root@aarch64 sbin]# chmod u+x mysql_db_backup.sh
  4. [root@aarch64 sbin]# ./mysql_db_backup.sh
  5. 2021-04-16_221712
  6. mysqldump: [Warning] Using a password on the command line interface can be insecure.
  7. 2021-04-16_221712/
  8. 2021-04-16_221712/2021-04-16_221712.sql.gz
  9. 备份数据库study成功^_^
  10. [root@aarch64 sbin]# ll /data/backup/db/
  11. total 4
  12. -rw-r--r-- 1 root root 1046 Apr 16 22:17 2021-04-16_221712.tar.gz
  13. [root@aarch64 sbin]# crontab -l
  14. 30 02 * * * /usr/sbin/mysql_db_backup.sh

源码
  1. #!/bin/bash
  2. #备份目录
  3. BACKUP=/data/backup/db
  4. #当前时间戳
  5. DATETIME=$(date +%Y-%m-%d_%H%M%S)
  6. echo "$DATETIME"
  7. #数据库地址
  8. HOST=localhost
  9. #数据库用户名
  10. DB_USER=root
  11. #数据库密码
  12. DB_PW=Mysql@3306
  13. #备份的数据库名
  14. DB_NAME=study
  15. #判断备份目录是否存在,不存在则创建相应目录
  16. [ ! -d "${BACKUP}/${DATETIME}" ] && mkdir -p "${BACKUP}/${DATETIME}"
  17. #备份数据库
  18. mysqldump -u${DB_USER} -p${DB_PW} --host=${HOST} -q -R --databases ${DB_NAME} | gzip > ${BACKUP}/${DATETIME}/$DATETIME.sql.gz
  19. #处理.gz文件为.tar.gz后缀
  20. cd ${BACKUP}
  21. tar -zcvf ${DATETIME}.tar.gz ${DATETIME}
  22. #删除备份前创建的目录
  23. rm -rf ${BACKUP}/${DATETIME}
  24. #删除10天以前备份的数据库文件
  25. find ${BACKUP} -name "*.tar.gz" -atime +10 -exec rm -rf {} \;
  26. echo "备份数据库${DB_NAME}成功^_^"