• Linux从入门到精通(十二)——shell编程


    文章篇幅较长,建议先收藏,防止迷路

    文章跳转
    Linux从入门到精通(八)——Linux磁盘管理go
    Linux从入门到精通(九)——Linux编程go
    Linux从入门到精通(十)——进程管理go
    Linux从入门到精通(十一)——计划任务go
    Linux从入门到精通(十二)——shell编程go

    shell编程

    1. shell和shell脚本

    1.1 shell

    • Shell是一种具备特殊功能的程序,它是介于使用者和UNIX/Linux操作系统之核心程序 ( kernel) 之间的一个接口。
    • 为了对用户屏蔽内核的复杂性,也为了保护内核 以免用户误操作造成损害,在内核的周围建立了一个外壳( shell ) 用户向shell提出要求 ,shell解释并将请求传给内核。
    • 查看当前环境所使用的shell : echo $SHELL, 每个用户的缺省shell在系统里的/etc/passwd 文件里被指定。

    常见的shell:

    • Bourne Shell (简称sh) :由AT&T贝尔实验室的 Steven. Bourne开发。目前几乎所有的Linux系统 都支持它,将其作为应急Shell使用。
    • C Shell (简称csh) :C Shell由加利福尼亚大学 伯克利分校开发。编程风格类似于C语言,健壮性不 如Bourne Shell。
    • Korn Shell (简称 ksh) :与Bourne Shell向下完全兼容。Korn Shell 的效率很高,其命令交互界面和编程交互界面都很好。
    • Bourne Again Shell ( 简称bash ) :是Bourne Shell 的增强版,已经成为最流行的Shell。能够提供环境变量以配置用户Shell环境, 支持历史记录,内置算术功能,支持通配符表达式,将常用命令内置简化。

    1.2 shell脚本

    Shell脚本:按照一定的语法结构把若干linux命令组合在一起,实现特定的功能。

    • Shell 脚本是纯文本文件。
    • Shell 脚本通常以.sh 作为后缀名,但不是必须。
    • Shell脚本是以行为单位的,在执行脚本的时候会分解成一 行一行依次执行。

    2. shell脚本创建和执行方式

    shell结构:

    1. 第一行一定要指明系统需要那种Shell解释用户的shell 程序, 如# !/bin/sh ,#!/bin/bash
    2. #注释行
    3. 命令和控制结构

    创建shell程序的步骤:

    1. 创建一个包含命令和控制结构的文件。

    2. 修改这个文件的权限,使它可以执行。

      chmod u+x
      
      • 1
    3. 执行

      ./xxxx.sh
      # 或者:
      bash xxxx.sh
      
      • 1
      • 2
      • 3

    3. shell变量

    像高级程序设计语言一样,Shell也提供说明和使用变量的功能。

    Shell只要有以下4种变量:

    1. 用户自定义的变量;
    2. 位置变量;
    3. 预定义变量;
    4. 环境变量;

    3.1 用户自定义的变量

    用户自定义变量名由字母和下划线组成,并且变量名第一个字母不能为数字。

    用户自定义变量定义:

    变量名=变量值
    
    • 1

    注意事项:

    • 变量不需声明,可直接使用或者赋值

    • 在给变量赋值时,等号两边一定不能留空格,若变量中本身就包含了空格,则整个字符串都要用双引号括起来。

    • 查看所有的变量,可以使用set命令;

      [root@localhost hadoop]# SUN=sun
      [root@localhost hadoop]# set|grep SUN
      SUN=sun
      
      • 1
      • 2
      • 3
    • 使用变量时,可以在变量名前面加一个美元符号$。建议在变量名字两边$后面加上{};

      [root@localhost hadoop]# echo ${SUN}
      sun
      [root@localhost hadoop]# echo ${SUN}day
      sunday
      [root@localhost hadoop]# echo $SUNday
      # 空
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
    • 使用readonly命令可以将变量定义为只读变量。

      readonly ABC=aaa
      
      • 1
    • 清除变量:

      unset 变量名
      
      unset SUN
      
      • 1
      • 2
      • 3
    • 三种特殊符号:

      1. ``反引号:执行反引号中命令,将结果赋给变量。
      2. ’‘单引号:原封不动的输出
      3. “” 双引号:括起来的字符除美元符号($)、反斜杠(\) 、反引号(`) 和双引号(")之外都将作为普通字符对待。
      [root@localhost hadoop]# H1=hello
      [root@localhost hadoop]# W1='${H1},world
      [root@localhost hadoop]# W2="${H1},world"
      [root@localhost hadoop]# echo ${W1}
      ${H1},world
      [root@localhost hadoop]# echo ${W2}
      hello,world
      
      [root@localhost etc]# ll
      总用量 4
      drwxr-xr-x. 2 huyuyang huyuyang 4096 1123 13:44 hadoop
      [root@localhost etc]# W3=`ll`
      [root@localhost etc]# echo ${W3}
      总用量 4 drwxr-xr-x. 2 huyuyang huyuyang 4096 1123 13:44 hadoop
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14

    3.2 位置变量

    ​ 位置参数是一种在调用Shell程序的命令行中按照各自的位置决定的变量,是在程序名之后输入的参数。$0是一个比较特殊的位置参数,用于表示脚本自己的文件名。

    • $0:脚本程序的名字。
    • $1,$2...$9:传递给脚本的某个参数,$1 代表第1个参数, $2代表第2个参数,依此类推。

    例子和预定义变量一起;

    3.3 预定义变量:

    预定义变量是在Shell一开始时就定义了的变量,由符号$和另一个符号组成的,只能使用,不能修改。

    • $#:传递到脚本的参数的数量;
    • $*:以"参数1参数2… "形式保存所有参数;
    • $@:以"参数1" “参数2” …形式保存所有参数;
    • $?:命令执行后返回的状态,0表示成功执行,其他值则表明执行错误;
    • $$:当前进程的进程号 ;
    • $!:后台运行的最后一个进程号;

    3.2-3 例子:

    [root@VM-24-17-centos shellstudy]# cat test.sh
    #!/bin/bash
    # 学习位置变量与预定义变量
    echo '$# is:' $#
    echo '$* is:' $*
    echo '$? is:' $?
    echo '$$ is:' $$
    echo '$@ is:' $@
    echo '$0 is:' $0
    echo '$2 is:' $2
    # 使test.sh拥有执行权限
    [root@VM-24-17-centos shellstudy]# chmod u+x test.sh
    [root@VM-24-17-centos shellstudy]# ./test.sh p1 p2 p3 p4
    $# is: 4
    $* is: p1 p2 p3 p4
    $? is: 0
    $$ is: 200606
    $@ is: p1 p2 p3 p4
    $0 is: ./test.sh
    $2 is: p2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    3.4 环境变量

    环境变量又称全局变量, 通常,由系统在启动时设置,环境变量一般用大写字母表示。

    1. 查看环境变量:env

      [root@VM-24-17-centos shellstudy]# env | grep JAVA_HOME
      JAVA_HOME=/usr/local/applications/java/jdk1.8.0_221
      CLASSPATH=%JAVA_HOME%/lib:%JAVA_HOME%/jre/lib
      
      • 1
      • 2
      • 3
    2. 使用export命令将变量添加到环境中, 作为临时的环境变量(一种全局变量)。

      [root@VM-24-17-centos shellstudy]# env | grep EMAIL
      [root@VM-24-17-centos shellstudy]# export EMAIL=2582952862@qq.com
      [root@VM-24-17-centos shellstudy]# env | grep EMAIL
      EMAIL=2582952862@qq.com
      
      • 1
      • 2
      • 3
      • 4

    3.5 变量替换

    可以使用以下几种变量替换形式(replacevar.sh):

    • ${var}:替换为变量本来的值。

    • ${var:-word}:如果变量var为空或已被删除,则返word,但不改变var的值。

      [root@VM-24-17-centos shellstudy]# echo ${SUN}
      # 空
      [root@VM-24-17-centos shellstudy]# echo ${SUN:-word}
      word
      [root@VM-24-17-centos shellstudy]# echo ${SUN}
      # 空
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
    • ${var:+word}:如果变量var被定义,则返word,但不改变var的值。

    • ${var:=word}:如果变量var为空或已被删除,则返word,并将变量var的值设置为word。

    • ${var:?message}:如果变量var为空或已被删除,则将消息message发送到标准输出错误中,可以用来检测变量var是否可以被正常赋值。这种替换出现在shell脚本中,脚本将停止运行。

      [root@VM-24-17-centos shellstudy]# echo ${SUN:?hyy}
      -bash: SUN: hyy
      
      • 1
      • 2

    【例子1】

    [root@VM-24-17-centos shellstudy]# vim replacevar.sh
    #!/bin/bash
    username=hyy
    a=${username:-`whoami`}
    b=${username:+`whoami`}
    c=${username:=`whoami`}
    echo "username=${username} a=${a}"
    echo "username=${username} b=${b}"
    echo "username=${username} c=${c}"
    echo "now, unsert username"
    unset username
    a=${username:-`whoami`}
    echo "username=${username} a=${a}"
    b=${username:+`whoami`}
    echo "username=${username} b=${b}"
    c=${username:=`whoami`}
    [root@VM-24-17-centos shellstudy]# chmod u+x replacevar.sh
    [root@VM-24-17-centos shellstudy]# ./replacevar.sh 
    username=hyy a=hyy
    username=hyy b=root
    username=hyy c=hyy
    now, unsert username
    username= a=root
    username= b=
    username=root c=root
    
    [root@VM-24-17-centos shellstudy]# echo ${SUN:?'var:SUN not exist'}
    -bash: SUN: var:SUN not exist
    
    • 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

    另外也可以通过如下操作取变量内容(modvar.sh)
    准备:

    [root@VM-24-17-centos shellstudy]# var=/dirl/dir2/file.txt
    
    • 1
    1. 求字符串的长度

      [root@VM-24-17-centos shellstudy]# echo ${#var}
      19
      
      • 1
      • 2
    2. 提取位置3到最后的字符

      [root@VM-24-17-centos shellstudy]# echo ${var:3}
      rl/dir2/file.txt
      
      • 1
      • 2
    3. 从位置3,开始提取5个字符

      [root@VM-24-17-centos shellstudy]# echo ${var:3:5}
      rl/di
      
      • 1
      • 2
    4. 从左边开始,删除最短匹配ir

      [root@VM-24-17-centos shellstudy]# echo ${var#*ir}
      l/dir2/file.txt
      
      • 1
      • 2
    5. 从左边开始, 删除最长匹配ir,这里的*表示删除

      [root@VM-24-17-centos shellstudy]# echo ${var##*ir}
      2/file.txt
      
      • 1
      • 2
    6. 从右边开始,删除最短匹配di,注意:这里的*在后面。

      [root@VM-24-17-centos shellstudy]# echo ${var%di*}
      /dirl/
      
      • 1
      • 2
    7. 从右边开始, 删除最长匹配di

    [root@VM-24-17-centos shellstudy]# echo ${var%%di*}
    /
    
    • 1
    • 2
    1. 用yst替换第一个匹配的root,如果需要把/替换掉,需要加转义字符\

      [root@VM-24-17-centos shellstudy]# echo ${var/dir/yst}
      /ystl/dir2/file.txt
      
      • 1
      • 2

    【例子2】

    [root@VM-24-17-centos shellstudy]# vim modvar.sh
    #!/bin/bash
    var=/dirl/dir2/file.txt
    echo ${#var}
    echo ${var:3}
    echo ${var:3:5}
    echo ${var#*ir}
    echo ${var##*ir}
    echo ${var%di*}
    echo ${var%%di*}
    echo ${var/dir/yst}
    unset var
    [root@VM-24-17-centos shellstudy]# chmod u+x modvar.sh 
    [root@VM-24-17-centos shellstudy]# ./modvar.sh 
    19
    rl/dir2/file.txt
    rl/di
    l/dir2/file.txt
    2/file.txt
    /dirl/
    /
    /ystl/dir2/file.txt
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    4. shell基本语法

    ​ 在shell中使用read命令从标准输入读入数据, 并将该数据赋值给变量;使用echo命令实现换行标 准输出操作。

    ​ 在进行计算整数变量值时,可以使用expr表达式let命令$()形式$[]形式实现。

    ​ test是Shell程序中的一个表达式,通过和Shell 提供的if等条件语句相结合可以方便地测试字符串、 文件状态和数字。

    4.1 read 命令

    read命令可以通过键盘输入为变量赋值:

    read[参数]变量名...

    • -p后面跟提示信息,即在输入前打印提示信息。

    • -n后跟一个数字,指定输入文本的长度,当输入的字符数目达到预定数目时,自动退出,并将输入的数据赋值给变量。

    • -S输入字符时不在屏幕上显示

    • read读入的变量可以有多个,第一个数据给第一个变量,第二个数据给第二个变量,如果输入数据个数过多,则最后所有的值都给最后一个变量。

      [root@VM-24-17-centos shellstudy]# read a b c
      1 2 3 4 5
      [root@VM-24-17-centos shellstudy]# echo ${c}
      3 4 5
      
      • 1
      • 2
      • 3
      • 4

    【例子】

    实例程序read.sh

    [root@VM-24-17-centos shellstudy]# vim read.sh
    #!/bin/bash
    read -p 'please input three numbers:' first second third
    echo "${first},${second},${third}"
    read -n1 -p 'please input y or n:' ans
    echo # 换行
    echo ${ans}
    unset first second third ans
    [root@VM-24-17-centos shellstudy]# chmod u+x read.sh 
    [root@VM-24-17-centos shellstudy]# ./read.sh 
    please input three numbers:1 2 3
    1,2,3
    please input y or n:y
    y
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4.2 echo 显示命令

    Shell使用echo命令实现标准输出,在屏幕上打印出指定的字符串:

    echo [选项] [字符串]
    
    • 1
    • -n:不在最后自动换行。
    • -e:启用反斜线控制字符的转换
    • -E:不处理转义字符。此为缺省(默认)选项;

    echo命令的转义符(echotest.sh):

    转义符含义
    \a从系统喇叭发送出声音
    \b向左刪除
    \c抑制输出后面的字符并且最后不换行
    \EESCAPE键
    \f换页字符
    \n换行字符
    \r回车键
    \ttab制表符
    \反斜线本身

    【例子】

    [root@VM-24-17-centos shellstudy]# vim echotest.sh
    #!/bin/bash
    echo -e "this \nis \na \ntest"
    echo -E "this \nis \na \ntest"
    echo "this \nis \na \ntest"
    echo -n "this is a test"
    echo ",bye"
    echo -e "this is a \ctest"
    [root@VM-24-17-centos shellstudy]# chmod u+x echotest.sh 
    [root@VM-24-17-centos shellstudy]# ./echotest.sh 
    this 
    is 
    a 
    test
    this \nis \na \ntest
    this \nis \na \ntest
    this is a test,bye
    this is a 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    4.3 数值计算

    对数字型变量计算可以使用如下方法:

    1. 用法 1:$((...))

      A=$((3+4))
      
      • 1
    2. 用法 2:$[..]

      B=$[3+5]
      
      • 1
    3. 用法3:expr表达式:

      C=`expr 5 + 4` #  注意运算符两侧必须有空格,否则出错
      
      • 1
    4. 用法4:let指令,计算并赋值:

      let D=5+5
      
      • 1

    【例子】

    [root@VM-24-17-centos shellstudy]# vim com.sh
    #!/bin/bash
    A=$((3+4))
    B=$[3+5]
    C=`expr 5 + 4`
    let D=5+5
    echo "${A},${B},${C},${D}"
    E=$((3+$((4+$((5+5))))))
    echo ${E}
    let E++
    echo ${E}
    unset A B C D E
    [root@VM-24-17-centos shellstudy]# chmod u+x com.sh 
    [root@VM-24-17-centos shellstudy]# ./com.sh 
    7,8,9,10
    17
    18
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    4.4 变量表达式测试

    ​ test命令在Shell脚本程序中主要用于测试一个表达式;如果条件为真,则返回一个0值。如果表达式不为真,则返回一个大于0的值——也可以将其称为假值。其语法如下:

    test 表达式
    
    • 1

    表达式所代表的操作符有字符串操作符、数字操作符、逻辑操作符以及文件操作符。

    4.4.1 字符串测试
    test表达式含义
    str1==str2当str1与str2相同时,返回真
    str1!=str2当str1与str2不同时,返回真
    str当str不为空字符串时,返回真
    -n str当str长度大于0时,返回真
    -z str当str长度为0时,返回真

    【例子】

    [root@VM-24-17-centos shellstudy]# vim strtest.sh
    #!/bin/bash
    echo -n "Enter your login name: "
    read name
    if test "${name}" == "root"; # 注意==两边的空格
    then    
            echo "hello,${name},How are you today?"
    else    
            echo "name error,so who are you?"
    fi 
    [root@VM-24-17-centos shellstudy]# chmod u+x strtest.sh
    [root@VM-24-17-centos shellstudy]# ./strtest.sh 
    Enter your login name: root
    hello,root,How are you today?
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    上面这种test…形式写起来比较复杂,通常使用下面的方式:

    if [ "${name}" = "root" ]; # 同样要注意[]两侧的空格
    
    • 1
    4.4.2 数值测试
    test表达式含义
    int1 -eq int2当int1等于int2时,返回真
    int1 -ge int2当int1大于/等于int2时,返回真
    int1 -le int2当int1小于/等于int2时,返回真
    int1 -gt int2当intl大于int2时,返回真
    int1 -lt int2当intl小于int2时,返回真
    int1 -ne int2当int1不等于int2时,返回真

    【例子】

    [root@VM-24-17-centos shellstudy]# vim inttest.sh
    #!/bin/bash
    if [ $# -ne 2 ]; then
            echo "not enough parameter"
            exit 0
    fi      
    if [ $1 -eq $2 ]; then
            echo "$1 equals $2"
    elif [ $1 -lt $2 ]; then
            echo "$1 littler than $2"
    elif [ $1 -gt $2 ]; then
            echo "$1 greater than $2"
    fi   
    [root@VM-24-17-centos shellstudy]# chmod u+x inttest.sh 
    [root@VM-24-17-centos shellstudy]# ./inttest.sh
    not enough parameter
    [root@VM-24-17-centos shellstudy]# ./inttest.sh 2 3
    2 littler than 3
    [root@VM-24-17-centos shellstudy]# ./inttest.sh 2 2
    2 equals 2
    [root@VM-24-17-centos shellstudy]# ./inttest.sh 3 2
    3 greater than 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    4.4.3 文件测试
    test表达式含义
    -d file当file是一个目录时,返回真
    -f file当file是一个普通文件时,返回真
    -r file当file是一个可读文件时,返回真
    -w file当file是一个可写文件时,返回真
    -x file当file是一个可执行文件时,返回真
    -s file当file文件长度大于0时,返回真

    【例子】

    [root@VM-24-17-centos shellstudy]# vim filetest.sh
    #!/bin/bash
    echo "please input a file name:"
    read file_name
    if [ -d $file_name ]; then
            echo "${file_name} is a directory"
    elif [ -f $file_name ]; then
            echo "${file_name} is a common file"
    elif [ -c $file_name ];then
            echo "${file_name} is a device file"
    else    
            echo "${file_name} is an unknown file"
    fi 
    [root@VM-24-17-centos shellstudy]# chmod u+x filetest.sh
    [root@VM-24-17-centos shellstudy]# ./filetest.sh 
    please input a file name:
    /etc
    /etc is a directory
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    4.4.4 逻辑测试
    test表达式含义
    !expr当expr的值是假时,返回真
    expr1 -a expr2当expr1和expr2值同为真时,返回真
    expr1 -o expr2当exprl和expr2的值至少有一个为真时,返回真

    变量测试语句一般不单独使用,一般作为if语句的测试条件,如:

    if test -d $1;then
    	...
    fi
    # 变量测试语句可用[]进行简化,如
    test -d $1 等价于 [ -d $1 ] ,切记[]两侧空格
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4.5 流程控制语句

    ​ 和其他高级程序设计语言一样,Shell提 供了用来控制程序和执行流程的命令,包括条件分支和循环结构,用户可以用这些命令创建复 杂的程序。

    ​ 与传统语言不同的是,Shell用于指定条件值的不是布尔运算式, 而是命令和字符串。

    4.5.1 If
    if [条件表达式]
    	then
    		语句序列
    fi
    # 如果你喜欢,也可以将 then 和 if 写在一行:
    if  [条件表达式];  then
        语句序列
    fi
    # -------------------------------------------------------------------------
    if [条件表达式]; then
    	语句序列1
    else
    	语句序列2
    fi
    # -------------------------------------------------------------------------
    if [条件表达式1]; then
    	语句序列1
    elif [条件表达式2]; then
    	语句序列2
    ...
    else
    	语句序列n
    fi
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    4.5.2 case
    case var in
    	表达式1)
    		...
    		;; 
    	表达式2)
    		...
    		;;
    	表达式3)
    		...
    		;;
        *) # 用通配符*来处理无匹配的情况,相当于其他语言中的default
        	...
    esac
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    【例子】

    [root@VM-24-17-centos shellstudy]# vim casetest.sh
    #!/bin/bash
    echo "*********************************"
    echo "please select your operation:" 
    echo "press "C" to copy"
    echo "press "D" to delete"
    echo "press "B" to backup"
    echo "*********************************"
    read op
    case $op in
            C)
                    echo "your selection is copy" ;;
            D)
                    echo "your selection is delete" ;;
            B)
                    echo "yourl selection 1s backup" ;;
            *)
                    echo "invalide selection"
    esac
    [root@VM-24-17-centos shellstudy]# chmod u+x casetest.sh 
    [root@VM-24-17-centos shellstudy]# ./casetest.sh 
    *********************************
    please select your operation:
    press C to copy
    press D to delete
    press B to backup
    *********************************
    C
    your selection is copy
    
    • 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

    4.6 循环结构

    在Shell程序中可以使用循环控制语句。

    1. 当循环次数已知或确定时,可以使用for循环语句来多次执行一条或一组命令,循环体由语句括号do和done来限定。
    2. 根据判断条件是否为真,使用while语句和until语句实现循环操作。
    3. 如果需要在未达到循环结束条件时强制跳出循环,通过breakcontinue实现。
    4.6.1 for
    1. for语法1:

      for 变量名 in 参数列表
      	do
      		命令列表
      	done
      
      • 1
      • 2
      • 3
      • 4

      将"参数列表"中的元素依次赋给"变量名“,在每次赋值后执行"命令列表”,"参数列表"表示"变量名"的取值范围。

      【例子】

      [root@VM-24-17-centos shellstudy]# vim for.sh
      #!/bin/bash
      for day in sunday monday tuesday wndnesday thursday friday saturday
      do      
              echo "this is : ${day}"
      done 
      [root@VM-24-17-centos shellstudy]# chmod u+x for.sh 
      [root@VM-24-17-centos shellstudy]# ./for.sh 
      this is : sunday
      this is : monday
      this is : tuesday
      this is : wndnesday
      this is : thursday
      this is : friday
      this is : saturday
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
    2. for语法2:

      这种和我们平时学的高级语言中的for循环差不多。

      for ((表达式1; 表达式2; 表达式3)) 
      do 
      	语句序列
      done
      
      • 1
      • 2
      • 3
      • 4
      • 表达式1: 赋值语句,循环结构的初始部分,为循环变量赋初值;
      • 表达式2:条件语句,循环结构的循环条件;
      • 表达式3:迭代语句,通常使用 ++ 或 – 运算符,循环结构的迭代部分,通常用来修改循环变量的值;

      【例子】

      [root@VM-24-17-centos shellstudy]# vim for2.sh
      #!/bin/bash
      for ((i=0; i <= 5; i++))
      do      
              echo "${i}"
      done    
      
      for ((i=1,j=10; i <= 5; i++,j=j+5))
      do      
              echo "Number ${i}: ${j}"
      done 
      [root@VM-24-17-centos shellstudy]# chmod u+x  for2.sh
      [root@VM-24-17-centos shellstudy]# ./for2.sh 
      0
      1
      2
      3
      4
      5
      Number 1: 10
      Number 2: 15
      Number 3: 20
      Number 4: 25
      Number 5: 30
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
    4.6.2 while

    语法:

    while [条件表达式]
    do 
    	命令列表
    done
    
    • 1
    • 2
    • 3
    • 4

    循环执行“命令列表”中的命令,直至“条件表达式”的值为假。

    4.6.3 until

    语法:

    until [条件表达式]
    do 
    	命令列表
    done
    
    • 1
    • 2
    • 3
    • 4

    循环执行“命令列表”中的命令,直至“条件表达式”的值为真。

    4.6.4 break 和 continue
    • break:终止当前循环
    • continue:忽略本次循环continue之后的语句,进入下一轮循环。

    4.7 函数

    4.7.1 函数的定义
    # 形式1:
    function 函数名 {
    	函数体
    }
    
    # 形式2:
    函数名(){	
    	函数体
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    注意:

    1. 第一种形式里,函数名和大括号之间要有空格;

      [root@VM-24-17-centos shellstudy]# vim func1.sh
      #!/bin/bash
      function testSum{
              let sum=3+4 # 注意,运算符两侧不要有空格
              echo "3+4=${sum}"
      }
      testSum
      
      [root@VM-24-17-centos shellstudy]# chmod u+x func1.sh
      [root@VM-24-17-centos shellstudy]# ./func1.sh
      ./func1.sh: line 3: syntax error near unexpected to ken `let'
      ./func1.sh: line 3: `        let sum=3+4 '
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

      可以看到并没有像想象中一样运行成功,而是报错了,意思有语法错误,在第三行let的地方(4.3 数值计算 有说let的使用),可是我们发现并没有错误, 那么我们就要看一下它周边的代码有没有问题,问题就出在空格:

      function testSum{ # 少了个空格
      function testSum { 
      
      • 1
      • 2
    4.7.2 函数调用
    函数名 #注意不需要括号
    # 如果需要参数
    函数名 参数1 参数2 ...
    
    • 1
    • 2
    • 3

    注意:

    1. 调用函数时传递的参数,在函数体中可以通过位置变量$1 $2 ...使用;

      [root@VM-24-17-centos shellstudy]# vim func1.sh
      #!/bin/bash
      testSum(){
              if [ $# -ne 2 ];then
                      echo "not enough parameters!"
                      echo "example ./func1.sh 1 2"
                      exit 0 # 正常退出
              fi
              let sum=$1+$2
              echo "$1+$2=${sum}"
      }
      testSum $1 $2 # 注意,这里不要忘记把参数传递给函数
      
      [root@VM-24-17-centos shellstudy]# ./func1.sh
      not enough parameters!
      example ./func1.sh 1 2
      [root@VM-24-17-centos shellstudy]# ./func1.sh 1 2
      1+2=3
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
    4.7.3 返回值
    [root@VM-24-17-centos shellstudy]# vim func1.sh
    #!/bin/bash
    testSum(){
            if [ $# -ne 2 ];then
                    echo "not enough parameters!"
                    echo "example ./func1.sh 1 2"
                    exit 0 # 退出
            fi
            let sum=$1+$2
            return ${sum}
    }
    testSum $1 $2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    如何访问到返回值:

    1. 通过$?(3.3 预定义变量 有说)访问:

      [root@VM-24-17-centos shellstudy]# vim func1.sh
      ...
      echo "$?"
      
      [root@VM-24-17-centos shellstudy]# ./func1.sh 1 2
      3
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      注意,如果通过这种方式,在调用函数和访问返回值之间不要出现其他语句

    4.7.4 递归

    实例:阶乘

    #!/bin/bash
    function fac {
            i=$1
            if [ ${i} -eq 1 ];then
                    echo 1
            else
                    let j=${i}-1
                    k=`fac ${j}`
                    echo `expr ${i} \* ${k}`
            fi
    }
    
    
    while true
    do
            read -p "please input an interger('q' to quit): " num
            if [ ${num} = 'q' ];then
                    break
            fi
            rtn=`fac ${num}`
            echo "answer is ${rtn}"
    done
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    注意:

    1. rtn=`fac ${num}`
      
      • 1

      并不是我们以为的那种获取函数返回值,echo xxx是输出到标准输出,fac函数通过echo将结果输出到标准输出,然后最终赋值给rtn的,``是返回命令的执行结果;

    4.8 数组

    1. 定义数组

      declear -a 变量名
      #或者
      变量名=(val1 val2 val3 ...)
      # 或者
      变量名=([下标1]=val1 [下标2]=val2 ...) #这个并不影响你获取的数组长度,不会因为你arr1=([10]=1),数组就长10,数组长度是你数组的元素个数。
      
      • 1
      • 2
      • 3
      • 4
      • 5
    2. 初始化

      数组名[index]=
      • 1
    3. 访问数组元素:

      ${数组名[${下标}]}
      
      • 1
    4. 访问数组长度(数组元素个数)

      ${#数组名[*]}
      
      • 1

    【例子1】

    [root@VM-24-17-centos shellstudy]# vim arr.sh
    #!/bin/bash
    arr1=(1 2 3 4)
    echo "arr1=[${arr1[*]}]"
    echo "len(arr1)=${#arr1[*]}"
    for ((i=0; i < ${#arr1[*]}; i++))
    do
            echo -n -e "${arr1[${i}]}\t"
    done
    echo ""
    
    [root@VM-24-17-centos shellstudy]# chmod u+x arr.sh
    [root@VM-24-17-centos shellstudy]# ./arr.sh 
    arr1=[1 2 3 4]
    len(arr1)=4
    1	2	3	4	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    【例子2】

    [root@VM-24-17-centos shellstudy]# vim arr2.sh
    #!/bin/bash
    arr1=([3]=1 [4]=2 [5]=3 [6]=4)
    echo "arr1=[${arr1[*]}]"
    echo "len(arr1)=${#arr1[*]}"
    
    echo "方法1"
    for ((i=0; i < ${#arr1[*]}; i++))
    do
            echo -n -e "${arr1[${i}]}\t"
    done
    echo ""
    
    echo "方法2"
    for var in ${arr1[*]}
    do
            echo -n -e "${var}\t"
    done
    echo ""
    
    [root@VM-24-17-centos shellstudy]# chmod u+x arr2.sh
    [root@VM-24-17-centos shellstudy]# ./arr2.sh 
    arr1=[1 2 3 4]
    len(arr1)=4
    方法1
    			1	
    方法2
    1	2	3	4	
    
    • 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

    注意:

    1. 下标从0开始
    2. 数组成员不必一定要连贯或连续的;
    3. 数组的一部分成员允许不被初始化;
    4. 数组中空缺元素是允许的;

    5. 补充

    1. 查看登录用户信息:
      1. who am i :当前登录用户,信息较为全面
      2. whoami: 只显示登录用户名
      3. who:较为全面的所有登录用户信息
      4. w:更全面的所有登录用户信息
  • 相关阅读:
    学生作业-购物网站-视频网站-仿百度网站-迪士尼网站-游戏网站-个人主页-个人介绍-音乐网站(作业源码)
    Vue学习之认识到应用(三)
    【离线/并查集】CF1213 G
    CVPR2023 RIFormer, 无需TokenMixer也能达成SOTA性能的极简ViT架构
    KWin、libdrm、DRM从上到下全过程 —— drmModeAddFBxxx(2)
    【设计模式】-创建型模式-第2章第1讲-【单例模式】
    网易云音乐项目
    Java泛型方法与普通成员方法以及案例说明(五)
    计算机基础之计算机的前沿技术
    NLP任务概览
  • 原文地址:https://blog.csdn.net/weixin_52000204/article/details/128007841