您的位置:首页 > 运维架构 > Shell

Shell脚本中获取命令运行结果、特殊变量使用、条件判断等常用操作

2020-07-11 00:49 148 查看

文章目录

  • 特殊变量使用
  • 条件判断
  • 总结
  • 前言

    最近在处理一个

    Python
    局部变量的作用域问题时发现有些奇怪,想起了之前常写的
    Lua
    脚本,于是想写个函数测试一下,结果发现短短的十几行代码出现了多个错误,这可是我写了近三年的代码啊,才放下半年就记不清了,所以知识这个东西还是要不断“温故”,今天要总结的
    Shell
    脚本命令也是,基本属于一看就会,一写不对的状态,所以还是要把常用的操作总结到一起,方便查找和复习。

    获取命令执行结果

    脚本中常常要获取一些命令的执行结果,比如当前目录

    pwd
    、当前时间
    date
    等等,如果在控制台时直接输入后回车就能看到结果,但是在
    Shell
    脚本中却不能这样做,常见的有以下两种方式。

    使用反引号
    `
    command
    `
    来执行命令

    反引号就是键盘上

    Tab
    键上方的那个按键对应的符号,常写 Markdown 的小伙伴知道这个符号就是包裹代码块的那个符号,在
    Shell
    脚本中被用来执行命令得到结果,举个简单的例子

    #!/bin/bash
    
    result=date
    echo $result
    
    result=`date`
    echo $result

    将上述命令保存到文件

    cmd.sh
    中运行
    ./cmd.sh
    得到结果:

    $ ./cmd.sh
    date
    Tue Jul 7 23:48:03 CST 2020

    从运行结果可以看出,如果不加反引号,我们常用的这些命令会被当成普通的字符串处理。

    使用括号组合 $(command) 来执行命令

    除了上面的反引号,使用美元符和小括号组合也可以在 Shell 脚本中运行命令,使用同样的例子测试

    #!/bin/bash
    
    result=`date`
    echo $result
    
    result=$(date)
    echo $result

    保存到文件

    cmd.sh
    中运行
    ./cmd.sh
    得到结果:

    $ ./cmd.sh
    Tue Jul 7 23:53:27 CST 2020
    Tue Jul 7 23:53:27 CST 2020

    对比可以看出两种方式在这个命令下运行结果是一样的。

    两种方式的区别

    虽然上述两种方式都可以在

    Shell
    脚本中得到命令运行的结果,但是有一点是不一样的,那就是反引号执行命令不支持嵌套,不能实现反引号中再出现反引号,而
    $(command)
    的方式是支持嵌套的,关于这一点可以看下面这个例子。

    $ echo $(ls $(pwd))
    cmd.sh

    分析一下这个命令

    echo $(ls $(pwd))
    ,最里面的命令是
    $(pwd)
    先执行得到当前目录,然后执行命令
    $(ls 当前目录)
    得到目录下的文件,再通过
    echo
    命令把这个结果输出,就得到了
    cmd.sh
    这个文件名,因为我这个目录下只有这一个文件。

    系统的命令使用反引号的方式改写就不生效了。

    $ echo `ls `pwd``
    cmd.shpwd

    我们还是仿照上面嵌套来写,但是

    echo
    后面的内容其实被分成了3部分,一个
    ls
    命令,一个
    pwd
    字符串、一个空命令,这样就能解释运行结果
    cmd.shpwd
    了。

    对照着结果我们就可以知道了,

    $(command)
    的方式更加强大,可以支持命令的嵌套,应用更广泛一点,而反引号的方式跟多出现在之前的脚本中。

    特殊变量使用

    从学习语言的第一天起就记住了变量名中只能有数字、字母、下划线,并且数字不能打头(Shell中只能字母开头),但是在

    Shell
    脚本中有一些特殊的变量,包含各种奇奇怪怪的符号。

    $0 $1 $2 …

    这些是运行

    Shell
    脚本时传递给脚本的命令行参数。命令行参数用 $n 表示,$0表示当前脚本的文件名,$1 表示第一个参数,$2 表示第二个参数,依次类推,可以类比 Windows 下的
    %0
    %1
    %2

    $$

    当前

    Shell
    脚本的进程ID。如果在命令行执行得到的是当前
    bash
    的进程ID,如果放到脚本中,得到的是脚本的进程ID。

    $?

    可以获取上一个命令执行后的返回结果。

    $#

    传递给脚本的命令行参数的个数。

    $*

    传递给脚本的命令行参数的所有参数。

    $@

    传递给脚本的命令行参数的所有参数,与

    $*
    稍有不同。

    测试

    写个脚本测试一下,新建

    cmdargs.sh
    文件,编写下面代码:

    #!/bin/bash
    
    echo \$0 is $0
    echo \$1 is $1
    echo \$2 is $2
    echo \$$ is $$
    echo \$# is $#
    echo \$* is $*
    echo \$@ is $@

    先执行

    ./cmdargs.sh
    脚本, 然后输出
    $?
    脚本的退出状态,运行结果如下:

    $ ./cmdargs.sh I love my daughter
    $0 is ./cmdargs.sh
    $1 is I
    $2 is love
    $$ is 197
    $# is 4
    $* is I love my daughter
    $@ is I love my daughter
    
    $ echo $?
    0

    $*
    $@
    的区别

    对照这个源码和输出结果,这些特殊变量应该可以分清楚了,其中

    $*
    $@
    都是把所有内容都列出来了,但它俩还是有点区别的,当这两个变量都被双引号包裹时,通过
    for
    循环会得到不同结果,写个脚本
    cmdargs2.sh
    试一下

    #!/bin/bash
    
    echo "test for \"\$*\""
    for var in "$*"
    do
    echo "$var"
    done
    
    echo "test for \"\$@\""
    for var in "$@"
    do
    echo "$var"
    done

    运行结果如下,

    "$*"
    把所有的参数当成了一个整体,而
    "$@"
    把各个参数都拆分开了,可以通过循环依次打印出来。

    $ ./cmdargs2.sh I love my daughter
    test for "$*"
    I love my daughter
    test for "$@"
    I
    love
    my
    daughter

    条件判断

    说起条件判断第一反应就是

    if
    了,在
    Shell
    脚本中也有
    if
    语句,同样是条件判断的中坚力量,先来看看
    if
    语句的写法:

    if
    语句格式

    if [ -d $filename ]; then
    echo "this is a directory."
    elif [ -a $filename ]; then
    echo "the file is exist."
    else
    echo "the file is not exist."
    fi

    直接提供一个最复杂的情况,如果不需要

    elif
    或者
    else
    分支,直接删掉就可以,但是
    if
    then
    fi
    这些都是必须的,并且中括号里面的表达式与中括号之间都要有空格,如果挨着写会报错的。

    中括号
    []
    的作用

    一度认为

    if
    条件语句就是这样写,中括号
    []
    应该是语法的一部分,但是查询后发现这居然是一个命令,和
    ls
    pwd
    一样是一个可以执行命令,放在
    if
    条件判断时基本等同于
    test
    命令。

    $ which [
    /usr/bin/[
    $ which test
    /usr/bin/test

    看着这个查询结果感觉神奇吧,此外还有一个

    [[]]
    双中括号的操作,这个就不是命令了,而是
    Shell
    的一个关键字,比
    []
    要强大的多。

    具体条件

    Shell
    脚本最常见的条件就是文件判断,数字判断和字符串判断了,接下来列举一下这些判断的常见写法。

    文件判断

    命令 含义
    -a $filename 文件存在时为真
    -d $filename 文件名对应的是目录时为真
    -s $filename 文件非空时为真
    -r $filename 文件可读时为真
    -w $filename 文件可写时为真
    -x $filename 文件可执行时为真

    数字判断

    命令 含义
    n1 -eq n2 n1等于n2时为真
    n1 -ne n2 n1不等n2时为真
    n1 -gt n2 n1大于n2时为真
    n1 -lt n2 n1小于n2时为真
    n1 -ge n2 n1大于等于n2时为真
    n1 -le n2 n1小于等于n2时为真

    字符串判断

    命令 含义
    -n str1 str1字符串不为空串时值为真
    -z str1 str1字符串为空串时值为真
    str1 == str2 str1与str2相等时为真
    str1 != str2 str1与str2不等时为真
    str1 > str2 按字典序str1排在str2后面时为真
    str1 < str2 按字典序str1排在str2前面时为真

    数字判断特殊写法

    命令 含义
    (("$n1" == "$n2"))
    n1等于n2时为真
    (("$n1" != "$n2"))
    n1不等n2时为真
    (("$n1" > "$n2"))
    n1大于n2时为真
    (("$n1" < "$n2"))
    n1小于n2时为真
    (("$n1" >= "$n2"))
    n1大于等于n2时为真
    (("$n1" <= "$n2"))
    n1小于等于n2时为真

    逻辑关系运算符

    命令 含义
    -a 与操作,用于
    []
    test
    操作符
    -o 或操作,用于
    []
    test
    操作符
    取反操作,用于
    []
    test
    操作符 和
    [[]]
    关键字
    && 与操作,用于
    [[]]
    关键字
    || 或操作,用于
    [[]]
    关键字

    这些逻辑写法千奇百怪的,写两个例子就慢慢就慢慢理解了,比如判断一个字符串不为空,并且这个字符串指定的目录还存在就可以写成

    if [ -n "$1" -a -d "$1" ]; then
    echo $1 directory is exist
    fi

    使用双小括号来比较数值变量,写在双小括号中的变量前面可以不加

    $
    符号,还有诸多特权等着你去发现

    num1=$1
    num2=$2
    if (( num1 > num2)); then
    echo num1 \> num2
    fi

    总之在学习这些条件比较的时候踩了不少坑,有很多情况都没有注意到,不过慢慢也适应了这种语法,但还是免不了会出现一个小问题,这里提供一个

    Shell
    语法检查的在线网站 《shellcheck》,将要检查的脚本放到页面上检测,会给出详细的错误信息,当然也有命令版本,可以自己到对应的 github 页面上下载哦~

    总结

    • Shell
      脚本中获取命令的执行结果,可以通过反引号
      `
      command
      `
      ,或者小括号
      $(command)
      的方式得到
    • Shell
      脚本中有一系列
      $
      开头的变量,用好他们是脚本和函数传递参数的关键
    • Shell
      脚本中的条件判断对于初学者来说很头大,有许多注意的点要记住,判断形式也多种多样
    • 脚本中有单引号、双引号、反引号,简单来记就是单引号中原样输出,双引号中变量求值后输出,反引号中只能写需要执行的命令
    • 脚本中还要中括号、双中括号、小括号、双小括号等,上面都提到过,可以自己练习下,具体的细节怕是要单独总结了,放到一起太多了
    • 脚本的中的分号起到语句结束的作用,如果有换行就不需要分号了,比如
      if
      条件后面的
      then
      如果换行,那么
      then
      前面的分号可以省略
    • 再记住一个坑,脚本赋值等号两端不能有空格,脚本判断等号两端必须有空格
    ==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==

    有些局,选择不入便立于不败之地,选择介入,即使曾身经百战,也恐难全身而退,更不要谈什么收益了~

    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: 
    相关文章推荐