• 【Shell】3万字图文讲解带你快速掌握shell脚本编程


    1、快速入门

    1.1、Shell介绍

    shell就是人机交互的一个桥梁 ;shell 本质上是 linux 命令,一条一条命令组合在一起,实现某一个目的,就变成了shell脚本。它从一定程度上 减轻了工作量,提高了工作效率。

    官方概念:

    Shell 通过提示您输入,向操作系统解释该输入,然后处理来自操作系统的任何结果输出,简单来说Shell就是一个用户跟操作系统之间的一个命令解释器。

    1.2、Shell编程需知

    • 命名规范:
      • 文件名一般为大小写英文、数字、-、_组成,但要记得见名知意
      • Shell脚本文件后缀名均为.sh
      • 编写Shell脚本时必须以#!/bin/bash做为首行来指定解释器

    1.3、编写第一个Shell脚本

    创建HelloWorld.sh

    [root@node100 shell_test]# vim HelloWorld.sh
    

    编写内容

    1. #!/bin/bash
    2. echo 'Hello World!!!'
    3. # echo 为打印输出

    执行脚本文件

    ① 给文件执行权限

    [root@node100 shell_test]# chmod +x HelloWorld.sh 
    

    ②执行脚本

    1. # 相对路径执行
    2. [root@node100 shell_test]# ./HelloWorld.sh
    3. # 绝对路径执行
    4. [root@node100 shell_test]# /shell_test/HelloWorld.sh

    注意:bash中的引号

    双引号"" :会把引号的内容当成整体来看待,允许通过$符号引用其他变量值
    

    单引号'' :会把引号的内容当成整体来看待,禁止引用其他变量值,shell中特殊符号都被视为普通字符 
    

    反撇号`` :反撇号和$()一样,引号或括号里的命令会优先执行,如果存在嵌套,反撇号不能用
    

    1.4、注释

    在编译过程中被解释器忽略的内容就称为注释。

    单行注释

    1. 单行注释格式:
    2. # 这是一个注释

    多行注释

    1. 多行注释格式:
    2. :<<EOF
    3. 注释内容...
    4. 注释内容...
    5. 注释内容...
    6. EOF
    7. 说明:EOF 也可以使用其他符号

    2、变量

    变量是用来临时保存数据的,该数据是可以变化的数据。

    2.1、变量定义

    定义语法:变量名=变量值

    ①定义变量

    [root@node100 shell_test]# a=123
    

    ②调用变量

    1. [root@node100 shell_test]# echo $a
    2. 或者
    3. [root@node100 shell_test]# echo ${a}

    ③删除变量

    [root@node100 shell_test]# unset a
    

    以上变量用法在Shell脚本中也同样使用

    2.2、变量的定义规则

    ①变量名区分大小写

    ②变量名不能有特殊符号

    特别说明:对于有空格的字符串给变量赋值时,要用引号引起来;

    ③变量名不能以数字开头但可以包含数字

    ④等号两边不能有任何空格

    ⑤变量名尽量做到见名知意

    2.3、变量的定义方式

    ①直接赋值给一个变量

    1. [root@node100 shell_test]# a=123456789
    2. [root@node100 shell_test]# echo ${a:2:3} # 表示从第3位开始截取,截取3个字符
    3. 345

    说明:

    $变量名${变量名}的异同

    相同点:相同点:都可以调用变量

    不同点:${变量名}可以只截取变量的一部分,而$变量名不可以

    ②命令执行结果赋值给变量

    1. [root@node100 shell_test]# a=`hostname`
    2. [root@node100 shell_test]# echo $a
    3. node100
    4. [root@node100 shell_test]# b=$(date)
    5. [root@node100 shell_test]# echo $b
    6. 20220730日 星期六 13:59:22 KST

    ③交互式定义变量(read)

    目的:让用户自己给变量赋值,比较灵活。

    语法:read [选项] 变量名 

    常见选项

    选项解释
    -p定义提示用户的信息
    -n定义字符数(现在变量长度)
    -s不显示(不显示用户的密码)
    -t定义超时时间,默认单位为秒(现在用户输入变量值的超时时间,单位为秒)

    举例1:让用户自己定义变量值

    [root@node100 shell_test]# read -p "请输入你的名字" name
    

    [root@node100 shell_test]# read -n6 a
    

    [root@node100 shell_test]# read -s pwd
    

    [root@node100 shell_test]# read -t1 a
    

    举例2:变量值来自文件

    注意:无论文件有多少内容,默认只取第一行内容作为变量值。

    ④定义有类型的变量(declare)

    目的:给变量做一些限制,固定变量的类型,比如:整型、只读

    用法:declare 选项 变量名=变量值

    常用选项:

    选项解释举例
    -i将变量看成整数declare -i A=123
    -r定义只读变量declare -r B=hello
    -a定义普通数组;查看普通数组
    -A定义关联数组;查看关联数组
    -x将变量通过环境导出declare -x A=123456 等于 export A=123456

    举例:

    凡是被-i选项修饰的变量,只能赋值整数。

    凡是被-r选项修饰的变量,为只读变量不能修改。

    2.4、系统变量

    系统变量(内置bash中变量) : shell本身已经固定好了它的名字和作用.

    内置变量含义
    $?返回上一条命令的执行状态;0表示执行正常,非0表示执行异常或错误
    $0当前执行的程序和脚本名
    $#脚本后面接的参数的个数
    $*脚本后面所有参数,参数当成一个整体输出,每一个变量参数之间以空格隔开
    $@脚本后面所有参数,参数是独立的,也是全部输出
    $1-$9脚本后面的位置参数,$1表示第一个位置参数,以此类推
    ${10}-${n}扩展位置参数,第10个位置变量必须用{}大括号括起来(2位数字以上括起来)
    $$先前所在进程的进程号
    $!后台运行的最后一个进程号
    !$调用最后一条命令历史中的参数

    2.5、变量扩展

    求变量长度:${#变量名}

    1. [root@node100 shell_test]# q=123
    2. [root@node100 shell_test]# echo ${#q}

    替换:${变量/old/new}将变量中第一次出现的old值替换成new值

    1. [root@node100 shell_test]# url=www.baidu.com
    2. [root@node100 shell_test]# echo ${url/w/x}

    替换:${变量//old/new}将变量中出现的old值全部替换成new值

    [root@node100 shell_test]# echo ${url//w/x}
    

    3、简单四则运算

    算术运算:默认情况下,shell就只能支持简单的整数运算

    运算内容:加(+)、减(-)、乘(*)、除(/)、求余数(%)

    3.1、四则运算符号

    表达式举例
    $(())echo $((1+1))
    $[]echo $[10-5]
    exprexpr 10 / 5
    letn=1;let n+=1等价于let n=n+1

    注意:在使用expr时一定要注意空格,而且在做乘法运算时一定要加引号,因为*在Linux中表示通配符。

    $(())

    $[]

    expr

    let

    3.2、i++++i

    i++:先打印i,后进行加1操作
    

    ++i:先进行加1操作,后打印i
    

    注意:除了i++++i外,i----i;expr不支持i++++i

    4、数组

    4.1、普通数组

    ①一次赋予一个值

    数组名[索引下标]=值

    1. [root@node100 shell_test]# qwe[0]=1
    2. [root@node100 shell_test]# qwe[1]=2
    3. [root@node100 shell_test]# qwe[2]=3

    访问:${数组名[元素下标]}

    [root@node100 shell_test]# echo ${qwe[0]}
    

    也可以通过declare -a 数组名的方式去声明数组

    ②一次赋予多个值

    数组名=(值1 值2 值3 ...)

    [root@node100 shell_test]# asd=(v1 v2 v3)
    

    访问:${数组名[元素下标]}

    [root@node100 shell_test]# echo ${asd[0]}
    

    ③将文件中每一行赋值给数组

    1. [root@node100 shell_test]# cat 1.txt
    2. qwe
    3. asd
    4. zxc
    5. rty
    6. [root@node100 shell_test]# zxc=(`cat 1.txt`)

    访问:${数组名[元素下标]}

    [root@node100 shell_test]# echo ${zxc[0]}
    

    4.2、关联数组

    ①声明关联数组

    声明方式:declare -A 数组名

    [root@node100 shell_test]# declare -A array
    

    ②数组赋值

    一次赋一个值

    语法:数组名[索引or下标]=变量值

    [root@node100 shell_test]# array[hello]=world
    

    访问数组中的值

    语法:echo ${数组名[索引or下标]}

    一次赋多个值

    语法:数组名=([下标1]=变量值1 [小标2]=变量值2 ... ...)

    1. [root@node100 shell_test]# declare -A array2
    2. [root@node100 shell_test]# array2=([1]=one [name]=tom [age]=18)

    访问

    语法:echo ${数组名[索引or下标]}

    [root@node100 shell_test]# echo ${array2[1]}
    

    访问数组中全部数据

    [root@node100 shell_test]# echo ${array2[*]}
    

    访问数组中的全部下标或索引名词

    [root@node100 shell_test]# echo ${!array2[*]}
    

    5、条件判断

    5.1、条件判断语法格式

    格式1: test 条件表达式

    格式2: [ 条件表达式 ] 

    格式3: [[ 条件表达式 ]]

    5.2、条件判断相关参数

    可以判断文件类型,判断文件新旧,判断字符串是否相等,判断权限等等..

    ①判断文件类型

    判断参数含义
    -e判断文件是否存在
    -f判断文件是否存在并且是一个普通文件
    -d判断文件是否存在并且是一个目录
    -L判断文件是否存在并且是一个软连接文件
    -b判断文件是否存在并且是一个块设备文件
    -S判断文件是否存在并且是一个套接字文件
    -c判断文件是否存在并且是一个字符设备文件
    -p判断文件是否存在并且是一个命名管道文件
    -s判断文件是否存在并且是一个非空文件(有内容)

    举例:test 条件表达式

    1. [root@node100 shell_test]# test -e a
    2. [root@node100 shell_test]# echo $?

    举例:[ 条件表达式 ] 

    1. [root@node100 shell_test]# [ -e 1.txt ]
    2. [root@node100 shell_test]# echo $?

    举例:[[ 条件表达式 ]]

    1. [root@node100 shell_test]# [[ -e 1.txt ]]
    2. [root@node100 shell_test]# echo $?

    ②判断文件权限

    判断参数含义
    -r当前用户对其是否可读
    -w当前用户对其是否可写
    -x当前用户对其是否可执行
    -u是否有suid,高级权限冒险位
    -g是否有sgid,高级权限强制位
    -k是否有t位,高级权限粘滞位

    举例:

    1. [root@node100 shell_test]# [ -r 1.txt ]
    2. [root@node100 shell_test]# echo $?

    1. [root@node100 shell_test]# [ -x 1.txt ]
    2. [root@node100 shell_test]# echo $?

    ③判断文件新旧

    说明:这里的新旧指的是文件的修改时间。

    判断参数含义
    file1 -nt file2比较file1是否比file2新
    file1 -ot file2比较file1是否比file2旧
    file1 -ef file2比较是否为同一个文件

    举例:

    1. [root@node100 shell_test]# [ 1.txt -nt demo1.sh ]
    2. [root@node100 shell_test]# echo $?

    ④判断整数

    判断参数含义
    -eq相等
    -ne不等
    -gt大于
    -lt小于
    -ge大于等于
    -le小于等于

    举例:

    1. [root@node100 shell_test]# [ 1 -eq 1 ]
    2. [root@node100 shell_test]# echo $?

    ⑤判断字符串

    判断参数含义
    -z判断是否为空字符串,字符串长度为0则成立
    -n判断是否为非空字符串,字符串长度不为0则成立
    string1 = string2判断字符串是否相等
    string1 != string2判断字符串是否不相等

    举例:

    1. [root@node100 shell_test]# [ a = a ]
    2. [root@node100 shell_test]# echo $?

    ⑥多重条件判断

    判断符号含义举例
    -a和&&逻辑与[ 1 -eq 1 -a 1 -ne 0 ]或者[ 1 -eq 1 ] && [ 1 -ne 0 ] 
    -o逻辑或[ 1 -eq 1 -o 1 -ne 0 ]

    特别说明:

    && 前面的表达式为真,才会执行后面的代码

    || 前面的表达式为假,才会执行后面的代码

    [root@node100 shell_test]# [ 2 -eq 2 ] && echo 'true'
    

    [root@node100 shell_test]# [ 2 -eq 1 ] && echo 'true'||echo 'false'
    

    5.3、类C风格的数值比较

    注意:在(( ))中,=表示赋值;==表示判断

    举例:

    注意:;只用于分割命令或表达式

    6、流程控制语句

    6.1、if语句

    语法结构:

    ① if结构

    1. if condition
    2. then
    3. command1
    4. command2
    5. ...
    6. commandN
    7. fi

    ② if...else结构

    1. if condition
    2. then
    3. command1
    4. command2
    5. ...
    6. commandN
    7. else
    8. command
    9. fi

    ③ if...elif...else结构

    1. if condition1
    2. then
    3. command1
    4. elif condition2
    5. then
    6. command2
    7. else
    8. commandN
    9. fi

    举例:

    编写if.sh文件

    1. #!/bin/bash
    2. read -p "请输入你的年龄" age
    3. if [ $age -ge 1 -a $age -le 18 ]
    4. then
    5. echo "年龄大于等于1并且小于等于18是未成年人"
    6. elif [[ $age -gt 18 ]]
    7. then
    8. echo "年龄大于18是成年人"
    9. else
    10. echo "请输入正确的年龄"
    11. fi

    执行if.sh文件

    1. [root@node100 shell_test]# chmod +x if.sh
    2. [root@node100 shell_test]# ./if.sh

    6.2、case语句

    语法结构

    1. case 变量名 in
    2. 变量值1)
    3. command1 需要执行的语句
    4. ;; 两个分号代表命令结束
    5. 变量值2)
    6. command2
    7. ;;
    8. 变量值3)
    9. command3
    10. ;;
    11. *) default,不满足以上模式,默认执行*)下面的语句
    12. command4
    13. ;;
    14. esac

    举例:

    编写case.sh文件

    1. #!/bin/bash
    2. read -p "请输入变量值" i
    3. case $i in
    4. 1)
    5. echo "你是第一名"
    6. ;;
    7. 2)
    8. echo "你是第二名"
    9. ;;
    10. 3)
    11. echo "你是第三名"
    12. ;;
    13. *)
    14. echo "你不是前三名"
    15. ;;
    16. esac

    执行

    1. [root@node100 shell_test]# chmod +x case.sh
    2. [root@node100 shell_test]# ./case.sh

    6.3、for循环语句

    语法结构:

    ①列表循环

    1. 列表for循环:用于将一组命令执行已知的次数
    2. 基本语法格式
    3. for variable in {list}
    4. do
    5. command
    6. command
    7. done
    8. 或者
    9. for variable in a b c
    10. do
    11. command
    12. command
    13. done

    举例(控制台):

    [root@node100 shell_test]# for i in {1..10};do echo $i;done
    

    [root@node100 shell_test]# for i in 1 2 3;do echo $i;done
    

    \

    1. [root@node100 shell_test]# for i in {1..10..2};do echo $i;done
    2. # {起始值..结束值..步长}

    [root@node100 shell_test]# for i in {10..1..2};do echo $i;done
    

    1. [root@node100 shell_test]# for i in $(seq 10);do echo $i;done
    2. # seq是个命令 seq [起始值] [步长] [结束值]

    ②不带列表循环

    1. for variable
    2. do
    3. command
    4. command
    5. done

    举例:

    编写for1.sh

    1. #!/bin/bash
    2. for i
    3. do
    4. echo $i
    5. done

    在执行的传参

    1. [root@node100 shell_test]# chmod +x for1.sh
    2. [root@node100 shell_test]# ./for1.sh 1 2 3

    ③类C风格的for循环

    1. for(( expr1;expr2;expr3 ))
    2. do
    3. command
    4. command
    5. done
    6. # expr1:初始条件
    7. # expr2:循环条件
    8. # expr3:迭代条件

    举例:

    编写for2.sh文件

    1. #!/bin/bash
    2. for((i=1;i<=5;i++))
    3. do
    4. echo $i
    5. done

    执行

    1. [root@node100 shell_test]# chmod +x for2.sh
    2. [root@node100 shell_test]# ./for2.sh

    6.4、while循环语句

    特点:条件为真就进入循环;条件为假就退出循环

    语法结构:

    1. while 表达式
    2. do
    3. command...
    4. done

    举例:

    编写while.sh文件

    1. #!/bin/bash
    2. i=1
    3. while ((i<=5)) # ((i<=5)) 也可以换成 [ $i -le 5 ]
    4. do
    5. echo $i
    6. let i++
    7. done

    执行

    1. [root@node100 shell_test]# chmod +x while.sh
    2. [root@node100 shell_test]# ./while.sh

    6.5、until循环

    特点:条件为假就进入循环;条件为真就退出循环

    语法结构

    1. until expression
    2. do
    3. command
    4. command
    5. ...
    6. done

    举例:

    编写until.sh文件

    1. #!/bin/bash
    2. i=1
    3. until [ $i -gt 5 ]
    4. do
    5. echo $i
    6. let i++
    7. done

    执行

    1. [root@node100 shell_test]# chmod +x until.sh
    2. [root@node100 shell_test]# ./until.sh

    6.6、循环控制语句

    continue:继续;表示循环体内下面的代码不执行,重新开始下一次循环

    break:打断;马上停止执行本次循环,执行循环体后面的代码

    exit:表示直接跳出程序

    举例:循环打印1-5,但不打印3

    编写continue.sh

    1. #!/bin/bash
    2. for((i=1;i<=5;i++))
    3. do
    4. if ((i==3))
    5. then
    6. continue
    7. fi
    8. echo $i
    9. done

    执行

    1. [root@node100 shell_test]# vim continue.sh
    2. [root@node100 shell_test]# ./continue.sh

    举例:循环打印1-5,但是但是打印到3的时候结束循环

    编写break.sh文件

    1. #!/bin/bash
    2. for((i=1;i<=5;i++))
    3. do
    4. echo $i
    5. if ((i==3))
    6. then
    7. break
    8. fi
    9. done
    10. echo "程序结束"

    执行

    1. [root@node100 shell_test]# chmod +x break.sh
    2. [root@node100 shell_test]# ./break.sh

    举例:循环打印1-5,但是但是打印到3的时候结束整个程序

    编写exit.sh文件

    1. #!/bin/bash
    2. for((i=1;i<=5;i++))
    3. do
    4. echo $i
    5. if ((i==3))
    6. then
    7. exit
    8. fi
    9. done
    10. echo "结束程序"

    执行

    1. [root@node100 shell_test]# vim exit.sh
    2. [root@node100 shell_test]# ./exit.sh

    7、函数

    7.1、函数概述

    shell中允许将一组命令集合或语句形成一段可用代码,这些代码块称为shell函数,给这段代码起个名字称为函数名,后续可以直接调用该段代码的功能。

    7.2、定义函数

    语法结构

    1. [ function ] 函数名(){
    2. 命令代码
    3. [ return [value]]
    4. # 在return后面写一个值(0-256) 然后通过 echo $? 查看状态值。
    5. # 若只写return则表示结束,return后面的代码将不会执行
    6. 命令代码
    7. }

    举例:编写求输入参数和的函数

    编写fun.sh文件

    1. #!/bin/bash
    2. function get_sum(){
    3. sum=0
    4. for i in $@
    5. do
    6. let sum+=i
    7. done
    8. return $sum # 也可以直接 echo
    9. }

    执行

    1. [root@node100 shell_test]# source fun.sh # 生效文件
    2. [root@node100 shell_test]# get_sum 1 2 3 # 调用函数并传参
    3. [root@node100 shell_test]# echo $? # 查看状态

  • 相关阅读:
    前端常见问题(vue-题库一)
    Ubuntu22.04 FTP 搭建以及挂载
    自适应控制——仿真实验二 用Narendra方案设计模型参考自适应系统
    Jenkins+Python自动化测试持续集成详细教程
    vue3知识点:provide 与 inject
    公约数(也叫公因数)|公倍数 |小知识|Golang
    Java8实战-总结23
    删除 Windows Server IIS 10 和 ASP.NET 中的 HTTP 响应标头
    LQ0250 n进制小数【程序填空】
    进一步理解函数
  • 原文地址:https://blog.csdn.net/Hao1999_/article/details/126080490