shell脚本编程

编程概述

程序组成

  • 程序:算法+数据结构
  • 算法:处理数据的方式
  • 数据结构:数据在计算机中的类型和组织方式
  • 数据:是程序的核心,程序为数据提供服务

编程风格

  • 面向过程语言
  • 面向对象

编程语言排行榜

1
https://www.tiobe.com/tiobe-index/

编程语言级别分类

低级语言

  • 机器:二进制的0和1的序列,称为机器指令。与自然语言差异太大,难懂、难写
  • 汇编:用一些助记符号替代机器指令,称为汇编语言

高级编#程语言

  • 编译:高级语言–>编译器–>机器代码文件–>执行,如:C,C++
  • 解释:高级语言–>执行–>解释器–>机器代码,如:shell,python,php,JavaScript,perl

强类型和弱类型语言

  • 强类型语言:不同类型数据操作,必须经过强制转换才同一类型才能运算,如java , c# ,
    python
  • 弱类型语言:语言的运行时会隐式做数据类型转换。无须指定类型,默认均为字符型;参与运算会自动进行隐式类型转换;变量无须事先定义可直接调用,如:bash ,php,javascript

shell脚本基本用法

shell脚本用途

  • 将简单的命令组合完成复杂的工作,自动化执行命令,提高工作效率
  • 减少手工命令的输入,一定程度上避免人为错误
  • 将软件或应用的安装及配置实现标准化
  • 用于实现日常性的,重复性的,非交互式的运维工作,如:文件打包压缩备份,监控系统运行状态并实现告警等

shell 脚本基本结构

shell脚本编程

​ 是基于过程式、解释执行的语言

编程语言的基本结构

  • 各种系统命令的组合

  • 数据存储:变量、数组

  • 表达式:a + b

  • 控制语句:if

  • shell脚本:包含一些命令或声明,并符合一定格式的文本文件

  • 格式要求:首行shebang机制

    1
    2
    3
    4
    5
    #!/bin/bash
    #!/usr/bin/python
    #!/usr/bin/perl
    #!/usr/bin/ruby
    #!/usr/bin/lua

shell脚本的创建

  • 第一步:使用文本编辑器来创建文本文件,第一行必须包括shell声明序列:注释开头#!

    1
    #!/bin/bash
  • 第二步:加执行权限,给予执行权限,在命令行上指定脚本的绝对或相对路径

  • 第三步:运行脚本,直接运行解释器,将脚本作为解释器程序的参数运行

shell脚本注释规范

  1. 第一行一般为调用使用的语言
  2. 程序名称,避免更改文件名为无法找到正确的文件
  3. 版本号
  4. 更改后的时间
  5. 作者相关信息
  6. 该程序的作用,及注意事项
  7. 最后是各版本的更新简要说明

第一个shell脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
[01:34:44 root@localhost ~]#vim  hello.sh

1 #!/bin/bash
2 #Author:张雪龙
3 #2022-08-06 01:37:12
4 # mail: 1024320609@qq.com
5 #############################
6
7 #经典写法
8 echo "hello, world"
9 #流行写法
10 echo 'Hello, world!'

shell执行方法种类

  1. bash + 脚本文件名

    1
    2
    3
    [01:43:24 root@localhost ~]#bash hello.sh 
    hello, world
    Hello, world!
  2. cat + 脚本文件名 |bash

    1
    2
    3
    [01:47:26 root@localhost ~]#cat hello.sh |bash
    hello, world
    Hello, world!
  3. bash < 脚本文件名

    1
    2
    3
    [01:47:51 root@localhost ~]#bash < hello.sh 
    hello, world
    Hello, world!
  4. chmod +x 脚本文件 ——》./脚本文件名

    1
    2
    3
    4
    5
    [01:48:20 root@localhost ~]#ll hello.sh 
    -rw-r--r--. 1 root root 177 8月 6 01:39 hello.sh
    [01:48:53 root@localhost ~]#chmod +x hello.sh
    [01:49:19 root@localhost ~]#./hello.sh
    hello, world
  5. 本方法可以实现执行远程主机的shell脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    [01:51:54 root@localhost ~]#yum install httpd -y
    [01:52:23 root@localhost ~]#systemctl start httpd
    [01:52:54 root@localhost ~]#cp hello.sh /var/www/html/
    [01:53:40 root@localhost ~]#ls /var/www/html/

    #方法1
    [01:58:34 root@localhost ~]# curl -s http://192.168.100.30/hello.sh |bash
    hello, world
    Hello, world!

    #方法2
    [02:01:15 root@localhost ~]#curl http://192.168.100.30/hello.sh 2>/dev/null |bash
    hello, world
    Hello, world!

    #方法3
    [02:08:15 root@localhost ~]#wget -qO - http://192.168.100.30/hello.sh |bash
    hello, world
    Hello, world!

  6. 远程主机运行本地shell脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [02:15:37 root@localhost ~]#bash test.sh 
    192.168.100.30 192.168.122.1
    [02:15:44 root@localhost ~]#ssh 192.168.100.31 /bin/bash < test.sh
    The authenticity of host '192.168.100.31 (192.168.100.31)' can't be established.
    ECDSA key fingerprint is SHA256:zK4fUjtCYg/mFj+ASqJf+rKYnp+cwdBrbhHJ5gFCAds.
    Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
    Warning: Permanently added '192.168.100.31' (ECDSA) to the list of known hosts.
    root@192.168.100.31's password:
    192.168.100.31 192.168.122.1

shell脚本案例

备份脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[02:32:52 root@localhost data]#cat /root/bak.sh 
#!/bin/bash
#Author:张雪龙
#2022-08-06 02:23:09
# mail: 1024320609@qq.com
#############################

echo -e "\033[1;32mStarting backup...\033[0m"
sleep 2
cp -av /etc/ /data/etc`date +%F`/
echo -e "\033[1;32mBackup is finished\033[0m"

[02:34:08 root@localhost data]#bash /root/bak.sh
[02:34:36 root@localhost data]#ll
总用量 12
drwxr-xr-x. 2 root root 6 8月 6 02:28 bak
drwxr-xr-x. 148 root root 8192 8月 6 01:52 etc2022-08-06

shell脚本调试

  • 只检测脚本中的语法错误,但无法检查出命令错误,但不真正执行脚本

    1
    bash -n /path/to/some_script
  • 调试并执行

    1
    bash -x /path/to/some_script
  • 用法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    [02:53:48 root@localhost data]#cat -A test.sh 
    #!/bin/bash$
    #Author:M-eM-<M- M-iM-^[M-*M-iM->M-^Y$
    #2022-08-06 02:38:28$
    # mail: 1024320609@qq.com$
    #############################$
    $
    echo line1$
    hostnam$
    cat > test.txt <<EOF $
    aaa
    bbb$
    ccc$
    EOF $
    $
    echo line2 $
    $
    [02:53:59 root@localhost data]#bash -n test.sh
    test.sh:行16: 警告:立即文档在第 9 行被文件结束符分隔 (需要 `EOF')

  • 总结:脚本错误常见的有三种

    • 语法错误,会导致后续的命令不继续执行,可以用bash -n 检查错误,提示的出错行数不一定是准确的
    • 命令错误,默认后续的命令还会继续执行,用bash -n 无法检查出来 ,可以使用 bash -x 进行观察
    • 逻辑错误:只能使用 bash -x 进行观察

shell变量

变量

表示命名的内存空间,将数据放在内存空间中,通过变量名引用,获取数据。

变量类型:

  • 内置变量,如:PS1,PATH,UID,HOSTNAME,$$,BASHPID,PPID,$?,HISTSIZE

  • 用户自定义变量

  • 不同的变量存放的数据不同,决定了以下

    • 数据存储方式
    • 参与的运算
    • 表示的数据范围
  • 变量数据类型:

    • 字符
    • 数值:整型、浮点型, bash 不支持浮点数

Shell中变量命名法则

  • 命名要求
    • 区分大小写
    • 不能使程序中的保留字和内置变量:如:if, for
    • 只能使用数字、字母及下划线,且不能以数字开头,注意:不支持短横线 “ - ”,和主机名相反

命名习惯

  • 见名知义,用英文单词命名,并体现出实际作用,不要用简写,如:ATM
  • 变量名大写
  • 局部变量小写
  • 函数名小写
  • 大驼峰StudentFirstName,由多个单词组成,且每个单词的首字母是大写,其它小写
  • 小驼峰studentFirstName ,由多个单词组成,第一个单词的首字母小写,后续每个单词的首字母是大写,其它小写
  • 下划线: student_name

变量定义和引用

变量的生效范围等标准划分变量类型

  • 普通变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效
  • 环境变量:生效范围为当前shell进程及其子进程
  • 本地变量:生效范围为当前shell进程中某代码片断,通常指函数

变量赋值

  • ```HTTP
    name=’value’

    1
    2
    3
    4
    5
    6
    7

    - value 可以是以下多种形式

    ```HTTP
    直接字串:name='root'
    变量引用:name="$USER"
    命令引用:name=`COMMAND` 或者 name=$(COMMAND)
  • 注意:变量赋值是临时生效,当退出终端后,变量会自动删除,无法持久保存,脚本中的变量会随着脚本结束,也会自动删除

  • 变量引用

    1
    2
    $name
    ${name}
    • 弱引用和强引用

      • “$name” 弱引用,其中的变量引用会被替换为变量值
      • ‘$name’ 强引用,其中的变量引用不会被替换为变量值,而保持原字符串
    • 范例:变量的各种赋值方式和引用

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      [02:54:02 root@localhost data]#name='zhang'
      [03:22:57 root@localhost data]#echo $name
      zhang

      [03:23:03 root@localhost data]#echo I am $name
      I am zhang

      [03:23:25 root@localhost data]#echo "I am $name"
      I am zhang

      [03:23:42 root@localhost data]#echo 'I am $name'
      I am $name

      [03:23:50 root@localhost data]#echo $USER
      root
      [03:25:40 root@localhost data]#name=$USER
      [03:26:08 root@localhost data]#echo $name
      root

      [03:27:11 root@localhost data]#USER=`whoami`
      [03:27:37 root@localhost data]#echo $USER
      root

    #当内容中包含空格,则最好用双引号
    [22:56:14 root@localhost ~]#echo $(seq 5)
    1 2 3 4 5
    [22:57:01 root@localhost ~]#echo “$(seq 5)”
    1
    2
    3
    4
    5
    [23:00:53 root@localhost ~]#name=”ni
    hao
    ya”
    [23:01:07 root@localhost ~]#echo $name
    ni hao ya
    [23:01:24 root@localhost ~]#echo “$name”
    ni
    hao
    ya

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    - 案例:变量引用

    ```sh
    [23:01:31 root@localhost ~]#name=zxl
    [23:03:29 root@localhost ~]#age=20
    [23:03:39 root@localhost ~]#echo $name $age
    zxl 20
    [23:03:52 root@localhost ~]#echo $name$age
    zxl20

    #注意“_”变量名包含下划线,需要中括号{}包含变量名
    [23:04:11 root@localhost ~]#echo $name_$age
    20
    [23:04:32 root@localhost ~]#echo ${name}__$age
    zxl__20
    • 案例:变量的间接赋值和引用

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
        [23:10:01 root@localhost ~]#name=zhang
      [23:13:27 root@localhost ~]#title=mage
      [23:13:49 root@localhost ~]#name=$title
      [23:14:05 root@localhost ~]#echo $name
      mage
      [23:14:09 root@localhost ~]#echo $title
      mage
      [23:14:26 root@localhost ~]#title=zhang
      [23:15:54 root@localhost ~]#echo $name
      mage
    • 案例:变量追加值

      1
      2
      3
      4
      5
      [23:19:17 root@localhost ~]#title=ni
      [23:20:19 root@localhost ~]#title+=" hao"
      [23:20:26 root@localhost ~]#echo $title
      ni hao

    • 案例:利用变量实现动态命令

      1
      2
      3
      4
      5
      6
      7
        [23:20:32 root@localhost ~]#hostname
      localhost.localdomain
      [23:21:47 root@localhost ~]#cmd=hostname
      [23:22:37 root@localhost ~]#$cmd
      localhost.localdomain
      [23:22:43 root@localhost ~]#$cmd -I
      192.168.100.30 192.168.122.1
    • 案例:set 显示已定义的所有变量

      1
      2
      3
      4
      5
      6
      7
        [23:25:10 root@localhost ~]#set |head -n 6
      BASH=/bin/bash
      BASHOPTS=checkwinsize:cmdhist:complete_fullquote:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:login_shell:progcomp:promptvars:sourcepath
      BASHRCSOURCED=Y
      BASH_ALIASES=()
      BASH_ARGC=()
      BASH_ARGV=()
    • 案例:unset删除变量

      1
      2
      3
      4
      5
        [23:25:24 root@localhost ~]#$cmd
      localhost.localdomain
      [23:27:24 root@localhost ~]#unset cmd
      [23:27:32 root@localhost ~]#$cmd
      [23:27:39 root@localhost ~]#
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
        $GREEN----------------------Host systeminfo--------------------$END
      echo -e "HOSTNAME: $RED`hostname`$END"
      #echo -e "IPADDR: $RED` ifconfig eth0|grep -Eo '([0-9]{1,3}\.){3}[0-9]
      {1,3}' |head -n1`$END"
      echo -e "IPADDR: $RED` hostname -I`$END"
      echo -e "OSVERSION: $RED$PRETTY_NAME$END"
      范例:
      echo -e "KERNEL: $RED`uname -r`$END"
      echo -e "CPU: $RED`lscpu|grep '^Model name'|tr -s ' '|cut -d : -
      f2`$END"
      echo -e "MEMORY: $RED`free -h|grep Mem|tr -s ' ' : |cut -d : -f2`$END"
      echo -e "DISK: $RED`lsblk |grep '^sd' |tr -s ' ' |cut -d " " -f4`$END"
      $GREEN---------------------------------------------------------$END
    • 综合案例1:显示系统信息

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
        [00:40:14 root@localhost ~]#bash showSystemInfo.sh
      ------------------------SYSTEMINF---------------------
      主机名: localhost.localdomain
      系统版本号: 8
      内核信息: 4.18.0-348.el8.x86_64
      CPU: 4
      IP地址: 192.168.100.30
      内存大小: 3.6Gi
      硬盘大小: 200G
      ------------------------SYSTEMINF---------------------
      [00:40:15 root@localhost ~]#cat showSystemInfo.sh
      #!/bin/bash
      # **********************************************************
      #
      # * Author : 张雪龙
      # * Email : 1024320609@qq.com
      # * Create time : 2022-08-06 23:43
      # * Filename : showSystemInfo.sh
      # * Description :
      #
      # **********************************************************

      RED="\E[1;31m"
      GREEN="echo -e \E[1;32m"
      END="\E[0m"
      . /etc/os-release
      echo -e $RED"------------------------SYSTEMINF---------------------"$END

      echo -e $RED"主机名: $(hostname)" $END
      echo -e $RED"系统版本号: $VERSION" $END
      echo -e $RED"内核信息: $(uname -r)" $END
      echo -e $RED"CPU: $(lscpu|sed -n '4p'|tr -s " "|cut -d" " -f2)" $END
      echo -e $RED"IP地址: $(ifconfig|sed -n '2p'|tr -s " "|cut -d" " -f3)" $END
      echo -e $RED"内存大小: $(free -h|grep '^Mem'|tr -s " "|cut -d" " -f2)" $END
      echo -e $RED"硬盘大小: $(lsblk|grep '^sd'|tr -s " "|cut -d" " -f4)" $END

      echo -e $RED"------------------------SYSTEMINF---------------------"$END
    • 综合案例2:数据备份

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      [01:11:28 root@localhost ~]#cat backup.sh 
      #!/bin/bash
      # **********************************************************
      #
      # * Author : 张雪龙
      # * Email : 1024320609@qq.com
      # * Create time : 2022-08-07 00:54
      # * Filename : backup.sh
      # * Description :
      #
      # **********************************************************


      RED="\E[1;31m"
      GREEN="echo -e \E[1;32m"
      END="\E[0m"

      $GREEN "开始备份" $END
      sleep 3
      BACK_URL=/data/backup/
      SRC_URL=/etc
      date=$(date +%F_%T)
      cp -av $SRC_URL ${BACK_URL}${SRC_URL}_$date
      $GREEN "备份完成" $END

      [01:12:01 root@localhost ~]#bash backup.sh
      开始备份
      备份完成
      [01:12:58 root@localhost ~]#
      [01:12:58 root@localhost ~]#ls /data/backup/
      2022-08-07_01:09:54 etc etc_2022-08-07_01:11:19 etc_2022-08-07_01:12:58

环境变量

  • 环境变量

    • 可以使子进程(包括孙子进程)继承父进程的变量,但是无法让父进程使用子进程的变量
    • 一旦子进程修改从父进程继承的变量,将会新的值传递给孙子进程
    • 一般只在系统配置文件中使用,在脚本中较少使用
  • 变量声明和赋值:

    1
    2
    3
    4
    5
    6
    #声明并赋值
    export name=VALUE
    declare -x name=VALUE
    #或者分两步实现
    name=VALUE
    export name
  • 显示所有环境变量:

    1
    2
    3
    4
    env
    printenv
    export
    declare -x
  • 查看指定进程的环境变量

    1
    2
    3
    4
    5
    #cat /proc/$PID/environ
    [01:21:17 root@localhost ~]#echo $BASHPID
    9311
    [01:22:16 root@localhost ~]#cat /proc/$BASHPID/environ
    USER=rootLOGNAME=rootHOME=/rootPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/binSHELL=/bin/bashTERM=xtermSELINUX_ROLE_REQUESTED=SELINUX_LEVEL_REQUESTED=SELINUX_USE_CURRENT_RANGE=XDG_SESSION_ID=12XDG_RUNTIME_DIR=/run/user/0DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/0/busSSH_CLIENT=192.168.100.1 14129 22SSH_CONNECTION=192.168.100.1 14129 192.168.100.30 22SSH_TTY=/dev/pts/0[01:22:30 root@localhost ~]#
  • 删除变量:

    1
    unset name
  • bash内建的环境变量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    PATH
    SHELL
    USER
    UID
    HOME
    PWD
    SHLVL #shell的嵌套层数,即深度
    LANG
    MAIL
    HOSTNAME
    HISTSIZE

只读变量

只读变量:只能声明定义,但后续不能修改和删除,即常量

  • 声明只读变量:

    1
    2
    readonly name
    declare -r name
  • 案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    [01:36:17 root@localhost ~]#readonly PI=3.1415926
    [01:36:58 root@localhost ~]#echo $PI
    3.1415926
    [01:37:04 root@localhost ~]#PI=3.14
    -bash: PI: 只读变量
    [01:37:12 root@localhost ~]#unset PI
    -bash: unset: PI: 无法取消设定: 只读 variable
    [01:37:21 root@localhost ~]#echo $PI
    3.1415926
    [01:37:40 root@localhost ~]#exit
    注销
    Connection closing...Socket close.

    Connection closed by foreign host.

    Disconnected from remote host(192.168.100.30) at 01:37:58.

    Type `help' to learn how to use Xshell prompt.
    [D:\~]$

    Connecting to 192.168.100.30:22...
    Connection established.
    To escape to local shell, press 'Ctrl+Alt+]'.

    ni hao ya zhang xue long
    Activate the web console with: systemctl enable --now cockpit.socket

    Last login: Sun Aug 7 00:14:03 2022 from 192.168.100.1
    [01:38:04 root@localhost ~]#echo $PI

    [01:38:08 root@localhost ~]#

位置变量

  • 位置变量:在bash shell中内置的变量, 在脚本代码中调用通过命令行传递给脚本的参数

    1
    2
    3
    4
    5
    6
    $1, $2, ... 对应第1个、第2个等参数,shift [n]换位置
    $0 命令本身,包括路径
    $* 传递给脚本的所有参数,全部参数合为一个字符串
    $@ 传递给脚本的所有参数,每个参数为独立字符串
    $# 传递给脚本的参数的个数
    注意:$@ $* 只在被双引号包起来的时候才会有差异
  • 案例1

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    [01:48:53 root@localhost ~]#bash /root/postion.sh 1 2 3 4 5 6 7 8 9 10 11 12
    0st arg is /root/postion.sh
    1st arg is 1
    2st arg is 2
    3st arg is 3
    10st arg is 10
    11st arg is 11
    The number of arg is 12
    All args are 1 2 3 4 5 6 7 8 9 10 11 12
    All args are 1 2 3 4 5 6 7 8 9 10 11 12
    The scriptname is postion.sh
    [01:49:07 root@localhost ~]#cat postion.sh
    #!/bin/bash
    # **********************************************************
    #
    # * Author : 张雪龙
    # * Email : 1024320609@qq.com
    # * Create time : 2022-08-07 01:43
    # * Filename : postion.sh
    # * Description :
    #
    # **********************************************************


    echo "0st arg is $0"
    echo "1st arg is $1"
    echo "2st arg is $2"
    echo "3st arg is $3"
    echo "10st arg is ${10}"
    echo "11st arg is ${11}"
    echo "The number of arg is $#"
    echo "All args are $*"
    echo "All args are $@"
    echo "The scriptname is `basename $0`"
  • $*和$@的区别

    • 当$*和$@没有被引用的时候,它们确实没有什么区别,都会把位置参数当成一个个体。(我们最好不要使用,因为如果位置参数中带有空格或者通配符的情况下,可能结果会和我们想要的不一样)

    • “$“ 会把所有位置参数当成一个整体(或者说当成一个单词),如果没有位置参数,则”$“为空,如果有两个位置参数并且IFS为空格时,”$*”相当于”$1 $2”

    • “$@” 会把所有位置参数当成一个单独的字段,如果没有位置参数($#为0),则”$@”展开为空(不是空字符串,而是空列表),如果存在一个位置参数,则”$@”相当于”$1”,如果有两个参数,则”$@”相当于”$1” “$2”等等

    • 案例:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      [root@centos8 scripts]#cat f1.sh
      #!/bin/bash
      echo "f1.sh:all args are $@"
      echo "f1.sh:all args are $*"
      ./file.sh "$*"
      [root@centos8 scripts]#cat f2.sh
      #!/bin/bash
      echo "f2.sh:all args are $@"
      echo "f2.sh:all args are $*"
      ./file.sh "$@"
      [root@centos8 scripts]#cat file.sh
      #!/bin/bash
      echo "file.sh:1st arg is $1"
      [root@centos8 scripts]#./f1.sh a b c
      f1.sh:all args are a b c
      f1.sh:all args are a b c
      file.sh:1st arg is a b c
      [root@centos8 scripts]#./f2.sh a b c
      f2.sh:all args are a b c
      f2.sh:all args are a b c
      file.sh:1st arg is a

退出状态码变量

  • $? 变量 保存状态码的相关数字,不同的值反应成功或失败,$?取值范例 0-255

    1
    2
    $?的值为0 #代表成功
    $?的值是1到255 #代表失败
  • 案例

    1
    2
    3
    [02:04:25 root@localhost ~]#ping 114.114.114.114 -c1 >/dev/null 
    [02:05:16 root@localhost ~]#echo $?
    0
  • 用户可以在脚本中使用以下命令自定义退出状态码

    1
    exit [n]
    • 注意:
      • 脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字
      • 如果exit后面无数字,终止退出状态取决于exit命令前面命令执行结果
      • 如果没有exit命令, 即未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后
        一条命令的状态码

展开命令行

  • 展开命令执行顺序

    1
    2
    3
    4
    5
    6
    7
    8
    9
    把命令行分成单个命令词
    展开别名
    展开大括号的声明{}
    展开波浪符声明 ~
    命令替换$() 和 ``
    再次把命令行分成命令词
    展开文件通配符*、?、[abc]等等
    准备I/0重导向 <、>
    运行命令
  • 防止扩展

    1
    反斜线(\)会使随后的字符按原意解释

    案例

    1
    2
    3
    4
    [root@centos8 ~]#echo Your cost: \$5.00
    Your cost: $5.00
    [root@rocky8 ~]#echo "The book's price is \$10"
    The book's price is $10
  • 加引号来防止扩展

    1
    2
    3
    `` : 反引号,命令替换
    \:反斜线,禁止单个字符扩展
    !:叹号,历史命令替换
  • 范例: ``和$() 区别

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    [02:05:23 root@localhost ~]#echo `echo \`
    > ^C
    [02:52:46 root@localhost ~]#echo `echo \\`
    \
    [02:52:52 root@localhost ~]#echo `echo \\\`
    > ^C
    [02:53:09 root@localhost ~]#echo `echo \\\\`
    \
    [02:53:12 root@localhost ~]#echo $(echo \)
    > ^C
    [02:53:35 root@localhost ~]#echo $(echo \\)
    \
    [02:53:39 root@localhost ~]#echo $(echo \\\)
    > ^C
    [02:54:21 root@localhost ~]#echo $(echo \\\\)
    \\
    • ``很容易与”搞混乱,尤其对初学者来说。
    • 在多层次的复合替换中,``必须要额外的转义字符处理(反斜线),而$( )比较直观。
    • 最后,$( )的弊端是,并不是所有的类unix系统都支持这种方式,但反引号是肯定支持的。

脚本安全和 set

​ set 命令:可以用来定制 shell 环境

  • $- 变量

    1
    2
    3
    4
    5
    6
    7
    8
    h:hashall,打开选项后,Shell 会将命令所在的路径hash下来,避免每次都要查询。通过set +hh
    项关闭
    i:interactive-comments,包含这个选项说明当前的 shell 是一个交互式的 shell。所谓的交互式shell,
    在脚本中,i选项是关闭的
    m:monitor,打开监控模式,就可以通过Job control来控制进程的停止、继续,后台或者前台执行等
    B:braceexpand,大括号扩展
    HhistoryH选项打开,可以展开历史列表中的命令,可以通过!感叹号来完成,例如“!!”返回上最近的
    一个历史命令,“!n”返回第 n 个历史命令

    案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    [root@centos8 ~]#echo $-
    himBHs
    [root@centos8 ~]#set +h
    [root@centos8 ~]#echo $-
    imBHs
    [root@centos8 ~]#hash
    -bash: hash: hashing disabled
    [root@centos8 ~]#echo {1..10}
    1 2 3 4 5 6 7 8 9 10
    [root@centos8 ~]#echo $-
    imBHs
    [root@centos8 ~]#set +B
    [root@centos8 ~]#echo $-
    imHs
    [root@centos8 ~]#echo {1..10}
    {1..10}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!