构建基本脚本

构建基本脚本

  • 在命令行中使用分号组织命令

    Shell脚本的关键在于输入多个命令并处理每个命令的结果,甚至需要将一个命令的结果传给另一个命令。Shell可以让你将多个命令串起来,一次执行完成。如果要两个命令一起运行,可以把它们放在同一行中,彼此间用分号隔开。

    使用分号一次执行两个命令
    [root@host1 /]# date;date Tue Jun 13 14:16:40 UTC 2023 Tue Jun 13 14:16:40 UTC 2023 [root@host1 /]# date;whoami Tue Jun 13 14:16:44 UTC 2023 centos
  • 基本的脚本构成

  1. 在Shell脚本中,井号#用作注释行,Shell并不会处理Shell脚本中的注释行。但是Shell脚本文件的第一行是个例外,#!符号是一个特殊的标记shabang,它会告诉系统用哪个Shell来运行脚本。
  2. 在Shell脚本中,你可以在独立的行中书写命令,Shell会按根据命令在文件中出现的顺序进行处理。
#!/bin/bash

# 脚本说明:测试指定IP地址的网络连通性
echo "--- 正在开始网络连通性测试 ---"
ip_domain='127.0.0.1 192.168.1.2'

for i in $ip_domain
do
    echo "正在探测: $i ..."
    ping -c 3 $i > /dev/null
    if [ $? -eq 0 ]
    then
        echo "[成功] 节点 $i 能够正常通讯"
    else
        echo "[失败] 无法连接到节点 $i"
    fi
done
echo "--- 测试任务已完成 ---"
exit 0

执行脚本文件的方式

在执行脚本时先查看脚本是否有执行权限

[root@host1 ~]# ls -l test.sh
-rwxrwxr-x 1 centos centos 124 Jun 13 14:51 test.sh
  • 第一种方式:在提示符中使用绝对、相对文件路径或者bash + 脚本名来引用脚本文件

    [root@host1 ~]# ./test.sh
    [root@host1 ~]# /root/test.sh
  • 第二种方式:将Shell脚本文件所处目录添加到PATH变量中

    [root@host1 ~]# echo $PATH
    /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
  • 第三种方式:使用 source + 脚本名 . + 脚本名进行调用

    [root@host1 ~]# . test.sh
    [root@host1 ~]# source test.sh

作业1:创建以下脚本,使用bash命令执行脚本,然后对脚本赋权后使用相对路径./test.sh的方式执行脚本。

  • 创建Shell脚本

    执行vim test.sh命令使用vim创建一个名为test.sh的脚本文件,编辑以下内容:

    #!/bin/bash
    
    # 向控制台打印欢迎信息
    echo "脚本正在运行..."
    echo "你好,世界!这是一条来自 Shell 脚本的消息。"
    echo "当前系统日期:$(date)"

Shell变量概念

  • 变量定义

    Shell变量是一种用于存储数据的容器。在Shell脚本中,变量用于存储各种类型的数据,例如数字、字符、字符串等。变量名通常是由一个字母、数字或下划线组成的字符串,并且不能以数字开头。

  • 变量分类

    Shell中主要有两种类型的变量:环境变量和自定义变量。环境变量是在系统中定义的,可以由所有进程和用户访问。常见的环境变量包括PATH、HOME和USER等。自定义变量是在脚本中定义的,只能在脚本中使用,不能在脚本外部访问。

  • 定义变量的语法格式: varName=varValue

    #!/bin/bash
        
    # 定义一个变量,变量名为var1,其值为数值 10
    var1=10
        
    # 定义一个变量,变量名为var2,其值为字符串 "你好,Shell"
    var2="你好,Shell"
        
    # 使用 echo 命令输出变量的值
    # 使用美元符号 $ 引导变量名来读取其内容
    echo "变量 var1 的当前值是: $var1"
    echo "变量 var2 的当前内容是: $var2"

    使用bash test.sh命令运行脚本:

    [root@host1 ~]# bash test.sh
    变量 var1 的当前值是: 10
    变量 var2 的当前内容是: 你好,Shell

Shell环境变量

环境变量定义

Bash Shell用环境变量(environment variable)来存储有关Shell会话和工作环境的信息(这也是它们被称作环境变量的原因)。这项特性允许你在内存中存储数据,以便程序或Shell中运行的脚本能够轻松访问到它们。这也是存储持久数据的一种简便方法。

环境变量分类

  1. 局部环境变量

    局部环境变量只能在定义它们的进程中可见。查看局部环境变量的列表有点复杂。在Linux系统并没有一个只显示局部环境变量的命令。set命令会显示为某个特定进程设置的所有环境变量,包括局部变量、全局变量以及用户定义变量。

    • 定义和使用局部变量

      区别于系统环境变量使用小写字符,当字符串内有空格时需要用双引号修饰。

      # 局部变量赋值时如果字符串内有空格不能直接赋值
      [root@host1 test]# my_var=Hello World
      bash: World: command not found
      [root@host1 test]# echo $my_var
      
      # 使用引号修饰字符串
      [root@host1 test]# my_var="Hello World"
      [root@host1 test]# echo $my_var
      Hello World

    局部变量在子Shell中不可用,同样子Shell中定义的局部变量在父Shell中不可用。

    # 在父shell中创建局部环境变量,并查看变量的值
    [root@host1 test]# my_var="Hello World"
    [root@host1 test]# echo $my_var
    Hello World
    # 使用bash创建子shell,在子shell中查看变量为空
    [root@host1 test]# bash
    [root@host1 test]# echo $my_var

    结合不同的脚本执行方式理解变量的作用范围、生命周期。

  2. 全局环境变量

    全局环境变量对于Shell会话和所有生成的子Shell都是可见的。局部变量则只对创建它们的Shell可见。这让全局环境变量对那些所创建的子Shell需要获取父Shell信息的程序来说非常有用。
    Linux系统在你开始bash会话时就设置了一些全局环境变量。系统环境变量基本上都是使用全大写字母,以区别于普通用户的环境变量。

    • 查看和使用全局环境变量

      [root@host1 test]# printenv HOME
      /root
      [root@host1 test]# echo $HOME
      /root
      # 使用'$'在shell中引用环境变量
      [root@host1 test]# ls $HOME
      test  test.sh
    • 全局环境变量可以用于所有子Shell

      # 在父shell中查看环境变量HOME
      [root@host1 test]# printenv HOME
      /root
      # 使用bash命令创建子shell
      [root@host1 test]# bash
      # 在子shell中查看HOME变量
      [root@host1 test]# printenv HOME
      /root
      # 查看当前系统的父子shell关系
      [root@host1 test]# ps -f
      UID          PID    PPID  C STIME TTY          TIME CMD
      centos       126     125  0 03:08 pts/3    00:00:00 bash
      centos       150     126  0 05:12 pts/3    00:00:00 bash
      centos       166     150  0 05:12 pts/3    00:00:00 ps -f
    • 设置全局环境变量

      在设定全局环境变量的进程所创建的子进程中,该变量都是可见的。创建全局环境变量的方法是先创建一个局部环境变量,然后再使用 export把它导出到全局环境中。

      # 在父shell中创建局部变量
      [root@host1 test]# my_var="Hello World"
      [root@host1 test]# echo "$$:$my_var"
      Hello World
      # 将局部变量导出为全局变量
      [root@host1 test]# export my_var
      # 创建子shell
      [root@host1 test]# bash
      # 查看子shell继承的全局变量
      [root@host1 test]# echo "$$ $my_var"
      Hello World
      # 修改子shell的全局变量
      [root@host1 test]# my_var="NULL"
      [root@host1 test]# echo "$$ $my_var"
      NULL
      # 退回父shell
      [root@host1 test]# exit
      exit
      # 父shell内的全局变量值没有变
      [root@host1 test]# echo "$$ $my_var"
      Hello World
    • bash默认的环境变量

      1. HOME:当前用户的家目录
      2. PATH:系统执行命令的路径
      3. USER:当前登录的用户名
      4. Shell:当前用户使用的默认Shell程序
      5. PWD:当前工作目录
      6. LANG:当前语言环境
      7. TERM:当前终端的类型
      8. PS1:命令提示符的格式
      9. HISTSIZE:命令历史记录的长度限制
      10. HISTFILESIZE:命令历史记录文件的大小限制

    作业2:通过以下方法设置全局环境变量$PATH后,在任意目录下直接执行脚本文件。

    • 设置PATH环境变量

      # 查看PATH变量的值
      [root@host1 test]# echo $PATH
      /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
      # 修改PATH变量,追加目录/root
      [root@host1 test]# PATH=$PATH:/root
      # 确认PATH变量的值
      [root@host1 test]# echo $PATH
      /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root

变量赋值

Shell脚本会自动决定变量值的数据类型。在脚本的整个生命周期里,Shell脚本中定义的变量会一直保持着它们的值,但在Shell脚本结束时会被删除掉。

  • 引用用户变量和环境变量

    • 使用等号将值赋给用户变量。在变量、等号和值之间不能出现空格。
    • 在脚本的整个生命周期里,Shell脚本中定义的变量会一直保持着它们的值,但在Shell脚本结束时会被删除掉。
    • 变量每次被引用时,都会输出当前赋给它的值。引用一个变量值时需要使用美元符,而引用变量来对其进行赋值时则不要使用美元符。没有美元符,Shell会将变量名解释成普通的文本字符串。
    #!/bin/bash
    
    # 通过引用环境变量进行赋值
    var1=$HOME
    
    # 通过echo命令打印var1的值
    echo "var1 = $var1"

    运行结果:

    [root@host1 ~]# bash test.sh
    var1 = /root
  • 命令替换

    Shell脚本中最有用的特性之一就是可以从命令输出中提取信息,并将其赋给变量。把输出赋给变量之后,就可以随意在脚本中使用了。这个特性在处理脚本数据时尤为方便。有两种方法可以将命令输出赋给变量:

    • 反引号字符(`)(与~同键位)
    • $()格式
    #!/bin/bash
    
    # 通过引用环境变量进行赋值
    today=`date +%y%m%d`
    
    touch log.$today

    运行结果:

    [root@host1 ~]# bash test.sh
    # 创建了一个后缀为当前系统时间的日志文件
    [root@host1 ~]# ls
    log.230616  test.sh

作业3:修改上述脚本,将创建的文件名格式改为主机名.当前日期,如localhost.230616,执行脚本创建文件后截图。

  • 从键盘读入赋值

    在Shell脚本中,Shell变量可以通过从键盘读入输入的内容并来赋值。命令格式为:read –p [提示信息]:[变量名]

    #!/bin/bash
    
    # 使用read命令打印出提示信息,等待用户输入字符并回车后将字符保存在变量ip内
    read -p "input ip:" ip
    
    # 使用ping检查用户所输入的ip地址的连通性
    ping -c2 $ip

变量的数值计算

  1. 使用 expr命令

    创建脚本test.sh、编辑以下内容:

    #!/bin/bash
    
    expr 5 + 2
    expr 5+2
    expr 5 * 2
    expr 5 \* 2

    运行脚本:

    [root@host1 ~]# bash test.sh
    # expr的用法里运算符两侧需要添加空格
    7
    5+2
    # 星号*不能直接作为乘法运算符使用,需要用反斜杠进行转义
    expr: syntax error
    10
  2. 使用括号

    创建脚本test.sh、编辑以下内容:

    #!/bin/bash
    
    var1=100
    var2=50
    var3=45
    
    var4=$((var1 / var2))
    var5=$((var1 / var3))
    
    echo var4 = $var4
    echo var5 = $var5

    运行脚本:

    [root@host1 ~]# bash test.sh
    var4 = 2
    # 使用括号进行的数值计算在整数范围内
    var5 = 2
  3. 在脚本内使用 bc 进行浮点数计算

    创建脚本test.sh、编辑以下内容:

    #!/bin/bash
    
    var1=`echo "scale=4; 3.44 / 5" | bc`
    
    echo the answer is $var1

    运行脚本:

    [root@host1 ~]# bash test.sh
    the answer is .6880
  4. 变量的自增

    Shell变量的自增运算符是i++++ii++表示先赋值再自加++i表示先自加再赋值

    创建脚本test.sh、编辑以下内容:

    #!/bin/bash
    
    var1=10
    
    ((var1++))
    echo $var1
    
    ((++var1))
    echo $var1
    
    var2=$((var1++))
    echo $var2 $var1
    
    var2=$((++var1))
    echo $var2 $var1

    运行脚本:

    [root@host1 ~]# bash test.sh
    11
    12
    12 13
    14 14

特殊参数

  • 位置参数

    $0表示脚本名,$1表示脚本传递的第一个参数,$2 表示传递的第二个参数。

    创建脚本test.sh、编辑以下内容:

    #!/bin/bash
    
    echo name is $0, var1 = $1, var2 = $2

    运行脚本:

    [root@host1 ~]# bash test.sh
    name is test.sh, var1 = , var2 =
    [root@host1 ~]# bash test.sh 123 abc
    name is test.sh, var1 = 123, var2 = abc
  • 预定义参数

    $0 脚本名
    $* 所有的参数(以整体的形式)
    $@ 所以的参数(以数组的形式)
    $# 参数的个数
    $$ 当前进程的PID
    $! 上一个后台进程的PID
    $? 上一个命令的返回值 0表示成功

作业4:修改上一个脚本,在脚本中使用预定义参数$#$@获取。

Shell中的特殊符号

  • “#”用在行首表示程序的注释。

  • “;” 作为命令的分隔符,分隔同一行上两个或者两个以上的命令。

  • “.”等价于source命令。它是bash中的一个内建命令。

    “.”也可以作为文件名的一部分,如果”.”放在文件名的开头,那么这个文件将会成为”隐藏文件”,ls命令将不会正常显示出这个文件。

  • 单引号’’,双引号””的区别是单引号’’剥夺了所有字符的特殊含义,单引号’’内就变成了单纯的字符。双引号””则对于双引号””内的参数替换($)和命令替换(``)是个例外。