云计算百科
云计算领域专业知识百科平台

Linux进阶打怪:Shell编程保姆级入门指南

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、先搞懂:Shell到底是什么?
    • 第一个Shell脚本:Hello World
    • 脚本的两种执行方式
  • 二、Shell变量:新手坑最多的地方
    • 1. 系统自带的变量
    • 2. 自定义变量:记住“等号两边没空格”
    • 3. 环境变量:全局生效的变量
    • 4. 位置参数变量:给脚本传参数
    • 5. 预定义变量:Shell提前定义好的
  • 三、Shell运算符:算数运算怎么写
  • 四、条件判断:逻辑控制的基础
    • 基本语法
    • 常用判断条件
      • (1)字符串比较
      • (2)整数比较
      • (3)文件权限判断
      • (4)文件类型判断
    • if分支语句
    • case分支语句
  • 五、循环语句:批量操作的神器
    • 1. for循环
      • 写法1:遍历参数/列表
      • 写法2:类C语言循环
    • 2. while循环
  • 六、read读取输入:让脚本可以交互
  • 七、Shell函数:封装复用代码
    • 1. 两个超实用的系统函数
    • 2. 自定义函数
  • 八、实战案例:MySQL定时自动备份
    • 需求
    • 脚本实现
    • 设置定时执行
  • 总结
    • 1、脚本基础
    • 2、四大变量
    • 3、算数运算
    • 4、条件判断
      • 分支语句
    • 5、循环
    • 6、交互输入read
    • 7、函数
    • 8、企业实战:MySQL定时备份

前言

这篇博客我就把Shell编程从入门到实战的核心内容全部整理出来,包括新手最容易踩的语法坑、高频必学的语法点、还有一个企业里真的会用的MySQL定时备份实战案例。全是自己踩坑总结出来的干货,建议收藏,学的时候对着敲一遍,基本就能上手用哩

一、先搞懂:Shell到底是什么?

很多人学了半天Shell,都没搞明白它到底是啥。其实一句话就能说清:Shell就是一个命令行解释器,是我们和Linux内核沟通的翻译官。

我们在终端敲的cd、ls这些命令,本质上都是先发给Shell,再由Shell解析后调用内核执行。而Shell编程,就是把一堆要执行的Linux命令,按照逻辑顺序写进一个文件里,让系统自动批量执行,不用我们手动一条一条敲。

Linux里最常用的Shell就是Bash,也是我们学习的重点。我们写的脚本文件通常以.sh结尾,这只是个约定俗成的标识,其实不影响执行,但规范起见还是建议加上。

第一个Shell脚本:Hello World

新手写第一个脚本,大概率会踩两个坑:忘了加脚本声明、忘了加执行权限。我当初两个坑全踩了,印象极其深刻。

一个标准的脚本长这样:

#!/bin/bash
# 我的第一个Shell脚本
echo "Hello World!"

  • 第一行#!/bin/bash是必须的,告诉系统这个脚本要用Bash解释器来执行;
  • #开头的是注释,脚本运行的时候会自动忽略。

脚本的两种执行方式

  • 赋予权限后直接执行(推荐)
  • # 给脚本添加可执行权限
    chmod u+x hello.sh
    # 相对路径执行
    ./hello.sh
    # 也可以用绝对路径执行
    /root/shellCode/hello.sh

  • 用sh命令直接调用(不用加权限)
  • sh hello.sh

    这种方式本质是直接用sh解释器去读文件,所以不需要文件本身有执行权限,临时测试的时候很方便。

    二、Shell变量:新手坑最多的地方

    Shell的变量分为四大类:系统变量、自定义变量、环境变量、特殊变量,其中细节特别多,尤其是空格规则,新手一不注意就报错。

    1. 系统自带的变量

    Linux内置了很多现成的变量,比如$HOME(当前用户家目录)、$PWD(当前所在绝对路径)、$SHELL(当前解释器)、$USER(当前用户名)。 想查看所有系统变量,直接输set就行,会列出当前Shell里所有的变量和函数。

    运行实例如下: 在这里插入图片描述

    2. 自定义变量:记住“等号两边没空格”

    这是我踩的第一个大坑!写A = 100报错了半天,后来才知道Shell里变量赋值,等号左右绝对不能有空格。

    #!/bin/bash
    # 正确写法:等号两边无空格
    A=100
    # 输出变量要加$符号
    echo A=$A
    echo "A=$A"

    # 撤销变量用unset
    unset A
    echo "撤销后A=$A"

    # 声明只读变量,不能修改也不能撤销
    readonly B=2
    echo "只读变量B=$B"

    还有几个命名规则要记住:

    • 变量名只能由字母、数字、下划线组成,不能以数字开头;
    • 变量名习惯全大写,算是行业默认规范;
    • 想把命令的执行结果赋值给变量,有两种写法:

    # 写法1:反引号(不推荐,容易和单引号搞混)
    C=`date`
    # 写法2:$()(推荐,清晰易读)
    D=$(date)

    3. 环境变量:全局生效的变量

    如果想让一个变量在所有Shell脚本里都能用,就要把它设成环境变量。 我们之前配置JDK的时候改的/etc/profile,里面写的就是全局环境变量。配置步骤很固定:

  • 用export 变量名=变量值把变量导出为环境变量;
  • 执行source 配置文件让修改立刻生效,不用重启系统;
  • 用echo $变量名就能查到变量值了。
  • 4. 位置参数变量:给脚本传参数

    我们写的脚本不可能永远写死内容,很多时候需要运行的时候传参数进去,这时候就要用到位置参数变量。 常用的就这几个:

    变量作用
    $0 脚本本身的文件名
    $n 第n个输入参数,n从1开始,10以上要写成${10}
    $* 所有输入参数,当成一个整体看待
    $@ 所有输入参数,每个参数相互独立
    $# 输入参数的总个数

    举个例子就懂了,写个脚本position.sh:

    #!/bin/bash
    echo "脚本文件名:$0"
    echo "第一个参数:$1"
    echo "第二个参数:$2"
    echo "所有参数(整体):$*"
    echo "所有参数(独立):$@"
    echo "参数总个数:$#"

    运行实例如下:

    运行./position.sh 100 200,输出结果一目了然。这里$*和$@的区别,在后面for循环里会体现得更明显。

    在这里插入图片描述

    5. 预定义变量:Shell提前定义好的

    这几个变量不用自己定义,直接就能用,写脚本判断状态的时候超实用:

    • $$:当前脚本运行的进程号(PID)
    • $!:后台运行的最后一个进程的进程号
    • $?:上一条命令的执行状态,0代表执行成功,非0代表执行失败

    尤其是$?,写脚本的时候判断上一步有没有执行成功,全靠它。

    三、Shell运算符:算数运算怎么写

    Shell里的算数运算不能直接写1+2,有三种固定写法,我个人最推荐第二种,省事又不容易错。

  • $((运算式))
  • $[运算式] ✅ 推荐
  • expr 运算式
  • 举个例子,计算3*(5+1):

    #!/bin/bash
    # 写法1
    RESULT1=$((3*(5+1)))
    echo "结果1:$RESULT1"

    # 写法2:最简洁,推荐用
    RESULT2=$[3*(5+1)]
    echo "结果2:$RESULT2"

    # 写法3:expr,运算符两边必须有空格,乘号要转义
    TEMP=`expr 5 + 1`
    RESULT3=`expr 3 \\* $TEMP`
    echo "结果3:$RESULT3"

    运行实例如下: 在这里插入图片描述 运行结果为: 在这里插入图片描述

    expr写法特别麻烦,空格、转义符很容易写错,日常写脚本基本都用$[],简单粗暴。

    四、条件判断:逻辑控制的基础

    基本语法

    [ 条件表达式 ]

    ⚠️ 巨坑提醒:中括号两边必须有空格![a=b]这么写必错,正确写法是[ a = b ]。

    条件为空的时候返回false,有内容就返回true,所以[ abc ]的结果是真,[ ]是假。

    常用判断条件

    (1)字符串比较

    • =:判断两个字符串是否相等
    • !=:判断两个字符串是否不相等

    (2)整数比较

    • -lt:小于(less than)
    • -gt:大于(greater than)
    • -le:小于等于
    • -ge:大于等于
    • -eq:等于
    • -ne:不等于

    (3)文件权限判断

    • -r:有读权限
    • -w:有写权限
    • -x:有执行权限

    (4)文件类型判断

    • -f:存在且是普通文件
    • -e:文件/目录存在
    • -d:存在且是目录

    if分支语句

    if语句的结尾是fi,就是if反过来写,刚开始记的时候觉得特别有意思。

    if分支语句中结尾fi必须加

    # 单分支
    if [ 条件 ]
    then
    执行代码
    fi

    # 多分支
    if [ 条件1 ]
    then
    代码1
    elif [ 条件2 ]
    then
    代码2
    else
    代码3
    fi

    # 判断文件是否存在
    if [ -f 文件的绝对路径 ]
    then
    代码
    fi

    举个经典例子:输入分数,判断等级

    #!/bin/bash
    if [ $1 -ge 80 ]
    then
    echo "优秀"
    elif [ $1 -ge 70 ]
    then
    echo "良好"
    elif [ $1 -ge 60 ]
    then
    echo "及格"
    else
    echo "不及格"
    fi

    运行结果如下: 在这里插入图片描述

    case分支语句

    case的结尾是esac,同样是反过来记。每个分支结尾要写两个分号;;。

    case $变量名 in
    "值1")
    代码1
    ;;
    "值2")
    代码2
    ;;
    *)
    默认执行的代码
    ;;
    esac

    执行结果如下: 在这里插入图片描述 在这里插入图片描述

    五、循环语句:批量操作的神器

    1. for循环

    for循环有两种常用写法,适用场景不一样。

    写法1:遍历参数/列表

    for 变量 in 值1 值2 值3
    do
    循环体
    done

    这个写法特别适合遍历输入参数,这里就能看出$*和$@的区别了:

    #!/bin/bash
    echo "—-测试\\$*—-"
    for i in "$*"
    do
    echo "参数:$i"
    done

    echo "—-测试\\$@—-"
    for i in "$@"
    do
    echo "参数:$i"
    done

    运行./test.sh 1 2 3,$*只会输出一行“参数:1 2 3”,而$@会输出三行,分别是1、2、3。 运行结果如下: 在这里插入图片描述

    在这里插入图片描述

    写法2:类C语言循环

    for((初始值;循环条件;变量变化))
    do
    循环体
    done

    运行结果如下: 在这里插入图片描述

    在这里插入图片描述

    经典例题:求1到100的和

    #!/bin/bash
    SUM=0
    for((i=1;i<=100;i++))
    do
    SUM=$[$SUM+$i]
    done
    echo "1-100的和是:$SUM"

    运行结果如下: 在这里插入图片描述

    2. while循环

    while循环和其他语言逻辑一样,条件满足就一直循环。

    while [ 条件 ]
    do
    循环体
    done

    同样用求1到100的和举例:

    #!/bin/bash
    SUM=0
    i=1
    while [ $i -le 100 ]
    do
    SUM=$[$SUM+$i]
    i=$[$i+1]
    done
    echo "总和是:$SUM"

    六、read读取输入:让脚本可以交互

    如果想让脚本运行的时候,提示用户输入内容,就要用到read命令。两个最常用的参数:

    • -p:指定提示文字
    • -t:指定等待超时时间,单位秒,超时就不等了

    举个例子:

    #!/bin/bash
    # 提示用户输入,不限时间
    read -p "请输入第一个数字:" NUM1
    # 提示用户输入,10秒内没输入就跳过
    read -t 10 -p "请输入第二个数字(10秒内):" NUM2
    echo "两个数的和是:$[$NUM1+$NUM2]"

    七、Shell函数:封装复用代码

    Shell里有系统自带的工具函数,也可以自己定义函数。

    1. 两个超实用的系统函数

    • basename:从完整路径里抠出文件名basename /home/test/a.txt # 输出 a.txt
      basename /home/test/a.txt .txt # 去掉后缀,输出 a
    • dirname:从完整路径里抠出文件所在的目录路径dirname /home/test/a.txt # 输出 /home/test

    处理文件路径的时候,这两个函数巨好用,不用自己写字符串切割。

    2. 自定义函数

    Shell函数的语法和其他语言有点不一样:参数不用写在括号里,调用的时候直接跟在函数名后面。

    #!/bin/bash
    # 定义函数
    function getSum(){
    SUM=$[$n1+$n2]
    echo "两数之和是:$SUM"
    }

    # 读取用户输入
    read -p "输入第一个数:" n1
    read -p "输入第二个数:" n2

    # 调用函数,参数直接写在后面
    getSum $n1 $n2

    ⚠️ 注意:函数必须定义在调用前面,Shell是从上往下执行的,先定义后调用。

    八、实战案例:MySQL定时自动备份

    学了这么多语法,总得做点实际的东西。这个MySQL备份脚本是企业里真的会用的,写完特别有成就感。

    需求

  • 每天凌晨2:30自动备份MySQL数据库;
  • 备份文件以备份时间命名,打包成tar.gz格式;
  • 自动删除10天前的旧备份文件;
  • 备份开始和结束给出提示。
  • 脚本实现

    #!/bin/bash
    # 备份文件存放目录
    BACKUP=/data/backup/db
    # 获取当前时间,格式:年月日_时分秒
    DATETIME=$(date +%Y-%m-%d_%H%M%S)

    echo "=====开始备份,时间:$DATETIME====="

    # 数据库配置
    HOST=localhost
    DB_USER=root
    DB_PW=你的数据库密码
    DATABASE=要备份的库名

    # 如果备份目录不存在,就自动创建
    [ ! -d "${BACKUP}/${DATETIME}" ] && mkdir -p "${BACKUP}/${DATETIME}"

    # 执行数据库备份并压缩
    mysqldump -u${DB_USER} -p${DB_PW} –host=${HOST} -q -R –databases ${DATABASE} | gzip > ${BACKUP}/${DATETIME}/${DATETIME}.sql.gz

    # 切换到备份目录,把整个文件夹打包成tar.gz
    cd ${BACKUP}
    tar -zcvf $DATETIME.tar.gz ${DATETIME}
    # 删掉原文件夹,只保留压缩包
    rm -rf ${BACKUP}/${DATETIME}

    # 删除10天前的备份文件
    find ${BACKUP} -atime +10 -name "*.tar.gz" -exec rm -rf {} \\;

    echo "=====备份完成,文件:$DATETIME.tar.gz====="

    设置定时执行

    脚本写好之后,用crontab设置定时任务就能全自动运行了:

    # 编辑定时任务
    crontab -e
    # 添加一行:每天凌晨2点30分执行脚本
    30 2 * * * /usr/sbin/mysql_db_backup.sh

    总结

    Shell(Bash)是Linux命令行解释器,Shell脚本就是把多条Linux命令编写到.sh文件实现批量自动化执行,是运维自动化的核心工具。

    1、脚本基础

  • 脚本首行声明:#!/bin/bash,指定Bash解释器。#代表注释。
  • 两种执行方式
    • chmod u+x xxx.sh && ./xxx.sh:添加执行权限后运行(推荐)
    • sh xxx.sh:直接调用解释器,不需要执行权限

    2、四大变量

  • 系统变量:$HOME、$PWD、$USER,set查看全部系统变量。
  • 自定义变量:A=100,等号两边不能有空格;取值$A;撤销unset A;只读readonly B=2。 命令结果赋值:D=$(date)(推荐),不推荐反引号`date`。
  • 环境变量:export 变量名=值导出全局变量;source 配置文件生效。
  • 位置参数变量
  • 变量作用
    $0 脚本文件名
    $1 $2…${10} 第1、2、10个参数
    $* 全部参数,作为一整个字符串
    $@ 全部参数,每个参数独立(循环常用)
    $# 传入参数总个数
  • 预定义变量
    • $$:当前脚本PID
    • $!:最后一个后台进程PID
    • $?:上一条命令返回状态,0成功,非0失败,脚本判断必备。

    3、算数运算

    优先用 $[表达式],简洁方便;也可用$((表达式));expr运算符前后必须空格,乘号\\*转义。

    res=$[3*(5+1)]

    4、条件判断

    语法:[ 条件 ],中括号内侧必须留有空格。

  • 字符串:=相等、!=不等
  • 整数:-lt小于、-gt大于、-le小于等于、-ge大于等于、-eq等于、-ne不等于
  • 文件:-f普通文件、-d目录、-e存在;权限-r -w -x
  • 分支语句

  • if语句,结束标记fi
  • if [ 条件 ];then
    ...
    elif [条件];then
    ...
    else
    ...
    fi

  • case语句,结束标记esac,每个分支末尾;;。
  • 5、循环

  • for循环
    • 遍历:for i in 值1 值2 值3; do … done,区分"$*"与"$@"
    • C风格计数:for((i=1;i<=100;i++));do … done
  • while循环:条件成立循环
  • while [ 条件 ]
    do
    done

    6、交互输入read

    • -p提示文字,-t超时秒数

    read -p "提示文字" num
    read -t 10 -p "10秒超时输入" num2

    7、函数

  • 内置工具
    • basename 获取文件名
    • dirname 获取目录路径
  • 自定义函数:必须先定义,后调用,参数直接跟函数名后面,不写括号。
  • function fun(){
    }
    fun 参数1 参数2

    8、企业实战:MySQL定时备份

  • 使用mysqldump做数据库备份,配合gzip压缩;
  • find命令清理N天前过期备份;
  • 配合crontab -e配置定时任务,实现定时自动备份。
  • 高频踩坑汇总

  • 变量赋值等号不能加空格
  • [ ]条件判断,括号内部两侧必须空格
  • if结尾fi、case结尾esac不能遗漏
  • "$*"与"$@"双引号包裹下循环行为不一样
  • 函数必须写在调用代码之前
  • $?判断上一步执行结果,自动化脚本必备
  • 赞(0)
    未经允许不得转载:网硕互联帮助中心 » Linux进阶打怪:Shell编程保姆级入门指南
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!