美文网首页
Shell系列之构建脚本

Shell系列之构建脚本

作者: QiShare | 来源:发表于2021-07-15 14:19 被阅读0次

    shell脚本的关键在于输入多个命令并处理每个命令的结果,甚至需要将一个命令的结果传给另一个命令。

    shell允许我们将多个命令串起来,一次执行完成。格式:多个命令放在一行中,彼此使用分号;隔开。如输出时间和登录用户:date +%Y%m%d;who

    qinwanlideMacBook-Pro:~ qinwanli$ date +%Y%m%d;who
    20203210/27/20
    qinwanli console  Oct 27 10:08 
    qinwanli ttys000  Oct 27 10:31 
    qinwanlideMacBook-Pro:~ qinwanli$ 
    

    上述date +%Y%m%d;who组成了一个简单的脚本,只不过这个脚本只用到了两个bash shell的命令。采用分号,分隔多命令的形式,会受到命令行最大字符数255的限制,并且每次都需要重新输入。因此,我们会将复杂的脚本,放到一个文本文件中,每次只需重新运行这个文本文件即可。

    shell脚本文件创建与运行

    关于shell脚本文件的创建,我们需要知道如何运用编辑器创建一个文件,具体可查看shell文件编辑器。也需知道shell文件内容的格式要求。

    在创建shell脚本文件时,必须在文件的第一行指定要使用的shell。其格式为:

    #! /bin/bash
    

    通常在shell脚本文件中,#用来注释行,但是shell脚本文件的第一行是例外,井号后的!会指定要运行该脚本的shell是哪一个(使用bash shell编写脚本,指定其他脚本执行也是可行的,如#! /bin/zsh)。

    shell脚本文件中,可以将多个命令放在同一行中彼此用;隔开,也可使用单独的行中书写。shell会根据命令在文件中出现的顺序执行。

    运行shell脚本文件,需保证shell能找到我们的shell脚本文件,有两种方式:

    • shell脚本文件所处的目录添加到PATH环境变量中;
    • 在提示符中用绝对或相对文件路径来引用shell脚本文件;

    接下来,我们将date +%Y%m%d;who这个简单的脚本写入shell脚本文件并执行,这个期间会经历一个重要的步骤,修改文件的权限

    #1.建个文件
    vim first_script
    #first_script文件内容:
      #! /bin/bash:
      #第一个用于测试的`shell`脚本
      #date +%Y%M%D
      #who
    
    #2.修改文件权限
    chmod u+x first_script
    #3.使用相对路径执行脚本
    ./first_script
    #4.输出
    20201410/27/20
    qinwanli console  Oct 27 10:08 
    qinwanli ttys000  Oct 27 10:31
    

    脚本运行的过程中,可以通过echo命令输出一些文本信息,来告诉用户,此刻脚本正在做什么。

    echo命令输出文本时,默认不需要使用引号,就能显示文本。

    qinwanlideMacBook-Pro:~ qinwanli$ echo good job
    good job
    

    特殊情况,字符串中出现引号,此时需要使用单引号或双引号,使用其中一个引用echo要输出的信息,使用另一个引用输出文本中带引号的文本。总之不能使用一样的引号。

    qinwanlideMacBook-Pro:~ qinwanli$ echo 'Rich says "scripting is easy".'
    Rich says "scripting is easy".
    qinwanlideMacBook-Pro:~ qinwanli$ echo "Rich says 'scripting is easy'."
    Rich says 'scripting is easy'.
    qinwanlideMacBook-Pro:~ qinwanli$ 
    

    为我们的脚本文件加点文本消息:

     #! /bin/bash:
     #第一个用于测试的`shell`脚本
     echo 输出系统的时间
     date
     echo 谁在登录
     who
    

    执行后输出:

    输出系统的时间
    2020年10月27日 星期二 11时34分06秒 CST
    谁在登录
    qinwanli console  Oct 27 10:08 
    qinwanli ttys000  Oct 27 11:20 
    

    文本消息与命令执行的结果处于同一行:echo -n msg
    修改脚本:echo -n 系统时间:;date
    执行输出:系统时间:2020年10月27日 星期二 11时37分20秒 CST

    使用变量

    echo命令中的环境变量会在脚本运行时替换成当前值,变量替换。shell脚本文件中使用环境变量的两种方式:

    • 变量名可被清楚识别时:在环境变量前加$
     #! /bin/bash
    echo 当前用户:$USER #当前用户:qinwanli
    echo "用户id:$UID 输出" #用户id:501 输出
    echo "用户的主目录:$HOME"#用户的主目录:/Users/qinwanli
    #注意
    #单引号,所引用变量,不会被解读
    echo '用户id:$UID 输出' #输出:用户id:$UID 输出
    
    • 变量名不能被清楚识别时:${variable}
    #! /bin/bash
    echo 用户${USER}已经开机
    echo "用户${USER}已经开机"
    

    注意:echo输出文本中引用变量,使用单引号,变量不会被解读,只能使用双引号"

    除了环境变量,shell允许用户在脚本中定义和使用变量。定义变量允许临时存储数据并在整个脚本中使用。

    var1=hello;var2=world
    var3=56
    var4="你好,世界"
    

    shell脚本会自动决定变量值的数据类型。在脚本的整个生命周期里,shell脚本中定义的变量会一直保持着它们的值,直到shell脚本结束时被删除掉。
    与系统变量类似,用户变量可通过美元符$引用,或${variable}引用。

    注意:引用一个变量的值时需要使用$,而引用别的变量来对其进行赋值时则不要使用$

    var1=hello;var2=world
    echo $var1 $var2 #hello world
    var1=hello;var2=world
    var3=$var2
    var4="$var3 !"#变量定义,变量值中有空格时,`bash shell`就会把值当成一个单独的命令,必须使用引号。
    echo "$var1 $var4"#hello world !
    

    命令替换

    命令替换:从命令输出中提取信息,并将其赋给变量。
    有两种方式可以将命令输出赋值给变量:

    • 反引号字符
    #! /bin/bash
    var=`date +%Y%m%d`
    echo $var #输出:20201027
    
    • $()格式
    #! /bin/bash
    var=$(date +%Y%m%d)
    echo $var #输出:20201027
    

    注意:命令替换会创建一个子shell来运行对应的命令。

    重定向输入和输出

    bash shell提供了几个操作符,可以将命令的输出重定向到另一个位置(比如文件)。重定向可以用于输入,也可以 用于输出,可以将文件重定向到命令输入。

    输出重定向

    最基本的重定向将命令的输出发送到一个文件中,bash shell用大于号(>)来完成这项功能,基本的命令格式:command > outputfile

    #时间输出到桌面的file1文件中
    date > ~/desktop/file1
    #查看
    vim ~/desktop/file1
    #显示 
       2020年10月27日 星期二 16时02分52秒 CST
    #登录用户输出到file1中
    who >  ~/desktop/file1
    #查看
    vim ~/desktop/file1
    #显示
      qinwanli console  Oct 27 10:08
      qinwanli ttys000  Oct 27 15:44
    

    综上命令执行,我们发现 > 重定向输出到同一个文件中时,文件中的内容会被覆盖。

    如果并不想覆盖文件原有内容,而是想要将命令的输出追加到已有文件中则使用双大于号>>命令。

    #继续追加数据到file1
    date >> ~/desktop/file1
    #查看
    vim ~/desktop/file1
    #显示
      qinwanli console  Oct 27 10:08
      qinwanli ttys000  Oct 27 15:44
      2020年10月27日 星期二 16时14分11秒 CST
    

    输入重定向

    输入重定向将文件的内容重定向到命令。
    操作符为小于号<,格式为:command < inputfile

    #文件内容输入到命令
    wc < ~/desktop/file1
    #输出
     3      14     112 file1
    

    wc命令会输出,输入的文本文件有多少行,多少单词,多少字节。

    还有另外一种输入重定向的方法,称为内联输入重定向(inline input redirection)。这种方法无需使用文件进行重定向,只需要在命令行中指定用于重定向输入的数据就可以了。

    内联输入重定向的操作符:双小于号<<,除了这个符号,我们还必须指定一个文本标记来划分输入数据的开始和结尾。任何字符串都可作为文本标记,但在数据的开始和结尾文本标记必须一致。
    格式为:

    command << marker#可以任何字符串,首尾必须一致
    data
    marker #可以任何字符串,首尾必须一致
    

    注意:在命令行上使用内联输入重定向时,shell会用PS2环境变量中定义的次提示符。
    具体使用:

    #输入
    wc << tag
    # step1: 回车,会出现次提示符,输入内容,
    > 大漠孤烟直
    > 长河落日圆
    # tip: 次提示符会持续提示,以获取更多的输入数据,直到我们输入了作为文本标记的那个字符串
    > tag # 意味输入数据结束,回车会执行`wc`
    #输出
     2       3      32
    

    管道

    有时需要将一个命令的输出作为另一个命令的输入。也可以用重定向来实现,只不过有些笨拙,比如:

    #文件信息重定向输出到file
    ls -l > file
    #对文件进行排序输出
    sort < file
    #输出排序后的结果
    

    一个命令的输出作为另一个命令的输入时,不需要将信息重定向到文件中,便可以将其直接重定向到另一个命令的过程,即为:管道连接。管道操作符:|,格式:command1 | command2

    注意:管道串起的两个命令并不是依次执行的。Linux系统实际上会同时运行这两个命令,在系统内部将它们连接起来。在第一个命令产生输出的同时,输出会被立即送给第二个命令。数据传输不会用到任何中间文件或缓冲区。

    具体使用:

    
     #列举目录下的内容,并排序
    qinwanlideMacBook-Pro:test qinwanli$ ls | sort
    #输出
    AppDelegate.h
    AppDelegate.m
    Assets.xcassets
    Base.lproj
    Info.plist
    SceneDelegate.h
    SceneDelegate.m
    ViewController.h
    ViewController.m
    main.m
    

    输出数据量比较大时,为了方便查看也可以管道执行moreless:

    ls | sort | more
    

    管道与重定向输出配合使用

    ls | sort > file
    

    数学运算

    shell脚本中有两种方式来处理数学运算:

    • expr命令;
    • 使用方括号[ ]

    expr执行数学运算

    expr执行数学运算,支持的操作符:

    `expr`支持的操作符.png

    终端使用:

    expr 1 + 5
    #输出:6
    expr 3 * 5
    #输出:expr: syntax error
    #解决办法,`*`加转义`\`
    expr 3 \* 5
    #输出:15
    

    shell脚本使用expr命令比较复杂,需要使用命令替换来获取expr命令的输出:

    #! /bin/bash
    #sample
    var1=3;var2=4
    echo "执行运算:$var1 * $var2"
    var3=$(expr $var1 \* $var2)
    echo 输出:$var3
    

    执行脚本输出:

    执行运算:3 * 4
    输出:12
    

    使用方括号

    bash shell为了保持跟Bourne shell(sh)的兼容而包含了expr命令,但它同样也提供了一种更简单的方法来执行数学表达式:$[operation]

    终端使用:

    echo $[1+5]
    #输出:6
    echo $[3*5]
    #输出:15
    

    脚本执行:

    #! /bin/bash
    #sample
    var1=3;var2=4
    echo "执行运算:$var1 * ($var2 - 1)"
    var3=$[$var1 * ($var2 - 1)]
    echo 输出:$var3
    

    执行脚本输出:

    执行运算:3 * (4 - 1)
    输出:9
    

    bash shell中使用方括号进行数学运算的最大的限制是浮点数的计算:

    echo $[3/2]
    #输出
    1
    

    bash中数学运算支持整数运算。

    值得一提的是zsh,提供了完整的浮点数算术操作。

    bash中浮点数算术运算

    那么如何在bash中进行浮点数的算术操作呢,答案是使用bash中内置的计算器,使用命令:bc
    bash计算器(bc),能够识别:

    • 数字(整数和浮点数)
    • 变量(简单变量和数组)
    • 注释(以#或C语言中的/* */开始的行)
    • 表达式
    • 编程语句(例如if-then语句)
    • 函数

    在终端使用bc进行运算:

    #输入`bc`
    qinwanlideMacBook-Pro:test qinwanli$ bc
    #输出
    bc 1.06
    Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.
    This is free software with ABSOLUTELY NO WARRANTY.
    For details type `warranty'.
    #出现运算输出提示符
    
    #输入
    3.14 * 2
    #回车,输出结果
    6.28
    #要退出`bc`时,必须输入`quit`
    quit
    #返回
    qinwanlideMacBook-Pro:test qinwanli$ 
    

    要退出bc时,必须输入quit

    浮点运算是由内建变量scale控制的。必须将这个值设置为我们希望在计算结果中保留的小数位数,否则无法得到期望的结果:

    qinwanlideMacBook-Pro:test qinwanli$ bc
    #默认的scale=0
    3.14 /5
    0
    #设置scale=2
    scale=2
    3.14 /5
    .62
    #设置scale=4
    scale=4
    3.14 /5
    .6280
    
    quit
    

    -q命令,可以在启动bash计算器时不显示其冗长的介绍信息。

    bc -q
    #开始输入
    3*4
    12
    

    bc中使用变量:

    qinwanlideMacBook-Pro:test qinwanli$ bc -q
    #定义变量
    var1=3
    var2=7
    var3=5
    #定义变量表达式
    var4=var1*(var2-var3)
    #利用print输出结果
    print var4
    6
    quit
    qinwanlideMacBook-Pro:test qinwanli$ 
    

    在脚本中使用bc:

    在脚本中使用bc,主要依赖于命令替换,将bc计算的结果赋值给脚本中定义的变量,脚本使用bc的基本格式:variable=$(echo "options; expression" | bc),解读:echo输出的字符串,通过管道输入到bc,进行执行后,输出,使用命令替换,将结果赋值给变量variable
    脚本使用bc实例如下:

    #! /bin/bash
    #脚本中使用bc
    echo 脚本中使用bc计算示例如下:
    
    echo 1.定义脚本变量
    
    var1=12.25
    var2=4.55
    
    echo 2.计算var1*var2使用'bc'进行计算,并将'bc'输出的结果,直接输出
    
    echo $(echo "scale=4;$var1*$var2" |bc)
    
    echo 3.计算var1/var2,将'bc'输出的结果,赋值给一个变量var3
    
    var3=$(echo "scale=2;$var1/$var2"|bc)
    
    echo 输出var3=$var3
    
    echo 4.计算var3*var1,将'bc'输出的结果,赋值给一个变量var4,并输出
    
    var4=$(echo "scale=4;$var3*$var1"|bc)
    
    echo 最终输出:var4=$var4
    

    执行脚本后输出

    qinwanlideMacBook-Pro:desktop qinwanli$ ./first_script 
    脚本中使用bc计算示例如下:
    1.定义脚本变量
    2.计算var1*var2使用bc进行计算,并将bc输出的结果,直接输出
    55.7375
    3.计算var1/var2,将bc输出的结果,赋值给一个变量var3
    输出var3=2.69
    4.计算var3*var1,将bc输出的结果,赋值给一个变量var4,并输出
    最终输出:var4=32.9525
    qinwanlideMacBook-Pro:desktop qinwanli$ 
    

    当脚本中使用bc,需要进行大量运算,在一个表达式中列出许多表达式比较麻烦,如:

    var4=$(echo "scale=4;var5=$var3*$var1;var5*10"|bc)
    

    bc可以识别内联重定向,因此可以使用这种可以使用内联重定向,将计算的表达式,输入到bc,格式如下:

    variable=$(bc << EOF
    options
    statements
    expressions
    EOF )
    

    使用示例

    #! /bin/bash
    #脚本中使用bc
    echo 脚本中使用bc计算示例如下:
    
    echo 1.定义脚本变量
    
    var1=12.25
    var2=4.55
    
    echo 2.采用内联重定向数据
    
    
    var4=$(bc << input
    scale=3
    var3=$var1*$var2
    var5=$var1+$var2
    var3+var5
    input
    )
    
    echo 最终输出:var4=$var4
    

    执行输出

    qinwanlideMacBook-Pro:desktop qinwanli$ ./first_script 
    脚本中使用bc计算示例如下:
    1.定义脚本变量
    2.采用内联重定向数据
    最终输出:var4=72.537
    qinwanlideMacBook-Pro:desktop qinwanli$ 
    

    退出脚本

    退出脚本:shell中运行的每个命令都使用退出状态码(exit status)告诉shell它已经运行完毕。退出状态码是一个0~255的整数值。
    默认情况下,命令成功退出的状态码是0:

    qinwanlideMacBook-Pro:~ qinwanli$ date
    2020年10月27日 星期二 20时57分31秒 CST
    qinwanlideMacBook-Pro:~ qinwanli$ echo $?
    0
    

    使用echo $?可以查看某个命令退出的状态码。默认情况下,shell脚本会以脚本中的最后一个命令的退出状态码退出。我们也可以主动为我们的脚本添加退出的状态码,保证它在0~255的范围内,也可以指定变量

    #! /bin/bash
    var=4
    exit $var
    #指定数字
    exit 0
    

    参考资料

    Linux命令行与shell脚本编程大全

    相关文章

      网友评论

          本文标题:Shell系列之构建脚本

          本文链接:https://www.haomeiwen.com/subject/lfoppltx.html