Code前端首页关于Code前端联系我们

为了在Linux下使用shell编程,需要掌握这些基础知识

terry 2年前 (2023-09-28) 阅读数 60 #未命名

在Linux下使用shell编程往往可以让我们的工作变得轻松很多。以下必要的知识你都掌握了吗?

输入参数和默认变量

在shell脚本中,有些内容是专门用来处理参数的,它们都有特定的含义,例如:

/home/shouwang/test.sh para1 para2 para3
$0                      $1    $2    $3
脚本名              第一个参数      第三个参数

其中$0代表要运行的脚本名称,$1 $2代表第一个和第二个参数。另外,还有一些其他的默认变量,比如:

#  代表脚本后面跟的参数个数,前面的例子中有3个参数
$@  代表了所有参数,并且可以被遍历
$*  代表了所有参数,且作为整体,和$*很像,但是有区别
$$  代表了当前脚本的进程ID
$?  代表了上一条命令的退出状态

变量

给变量赋值,使用等号,但是等号两边不能有空格,等号字符串右侧有空格的字符串也必须用引号引起来:

para1="hello world"  #字符串直接赋给变量para1

unset 用于停用变量。例如:

unset para1

如何使用变量?使用变量时,需要在变量前添加$。例如,如果要打印上一段内容1:

echo "para1 is $para1"
#将会输出 para1 is hello world

或在变量名称两边添加大括号:

echo "para1 is ${para1}!"
#将会输出 para1 is hello world!

执行命令

如果要在 shell 中运行命令,通常只要像在终端中一样执行命令即可,但是如果你想打印命令的结果,这个方法就行不通了。因此,shell 命令方法通常包括:

a=`ls`   #`是左上角~键,不是单引号

或使用 $ 后跟括号中的命令:

echo "current path is $(pwd)"   #

另外,前两种方法不适用于计算表达式,必须使用以下方法:

echo "1+1=$((1+1))"  #打印:1+1=2

即,在 $ 后面使用 双括号将要计算的表达式 括起来。

如果要执行的命令存储在变量中怎么办?以前的方法不再可行。当然,括号内的内容仍然是作为命令执行的。比如要使用下面的方法:

a="ls"
echo "$($a)"

但是,如果字符串中包含多个命令,上面的方法就不可行了,必须使用下面的方法:

a="ls;pwd"
echo "$(eval $a)"

这个使用eval来改变item的内容都是作为命令执行。

条件分支

一般描述,如果语句执行成功,返回值为0,否则为非0。因此,执行上一条命令的结果可以如下判断:

if [ $? -eq 0 ]
then
    echo "success"
elif [ $? -eq 1 ]
then
    echo "failed,code is 1"
else
    echo "other code"
fi

case命令的使用方法如下:

name="aa"
case $name in
    "aa")
    echo "name is $name"
    ;;
    "")
    echo "name is empty"
    ;;
    "bb")
    echo "name is $name"
    ;;
    *)
    echo "other name"
    ;;
esac

初学者要特别注意以下几点:

  • []前面必须有一个包含逻辑表达式
  • if 的空格必须跟在 elif 后面,后面跟要执行的命令
  • 要打印上一个命令的执行结果,最好赋值 $ ?到一个变量,因为一旦执行该语句,$? 的值就被改变了。它可能会改变。
  • 每个 case 分支都以两个分号结尾,最后一个 case 反向书写,即 esac。

如何使用多个条件?有两种方法。方法一:

if [ 10 -gt 5 -o 10 -gt 4 ];then
    echo "10>5 or 10 >4"
fi

方法二:

if [ 10 -gt 5 ] || [ 10 -gt 4 ];then
    echo "10>5 or 10 >4"
fi

其中 -o 或 ||意味着或。还有一些常见的条件句。

总结如下:

  • -o或or,同||
  • -a和a,同&&
  • ! no-

整数判断:

  • -eq 两个数是否相等
  • -no 这两个数是否不相等
  • -gt 第一个是否大于第二个(也更大)❙⼼ - lt 第一个是否小于第二个(小于)
  • -ge 第一个是否大于或等于第二个(大于或等于)
  • -le 第一个是否小于或等于第二个(小于或等于)

计算字符串 str1 exp str2:

  • -z "$str1" str1 是否为空字符串
  • -n " $str1" str1 是否不是空字符串
  • "$str1" == "$str2" str1是否等于str2
  • "$str1" != "$str2" str1是否不等于str2
  • " $str1" =~ " str2" str1是否包含str2

特别注意,字符串变量最好用引号括起来,因为一旦字符串中有空格,这个表达式就会出错,有兴趣的话可以尝试比较 str1="hello world" 和 str2="hello" 的情况。

评估文件目录:file_name

  • -f $filename 文件是否存在
  • -e $filename 是否存在
  • -d $filename 目录
    • 文件是否存在且不为空
    • ! -s $filename 文件是否为空

    循环

    循环一与 Python 非常相似:

    #遍历输出脚本的参数
    for i in $@; do
      echo $i
    done

    循环二与 C 风格非常相似:

    for ((i = 0 ; i < 10 ; i++)); do
      echo $i
    done

    打印循环 0。

    重复形式三:

    for i in {1..5}; do
        echo "Welcome $i"
    done

    循环打印 1 至 5。

    循环方法四:

    while [ "$ans" != "yes" ]
    do
       read -p "please input yes to exit loop:" ans
    done

    仅当输入 yes 时才会退出循环。这意味着当条件满足时,循环就会被执行。

    第五种迭代方法:

    ans=yes
    until [ $ans != "yes" ]
    do
       read -p "please input yes to exit loop:" ans
    done

    这意味着只有当ans不为yes时才会退出循环。

    重复方法六:

    for i in {5..15..3}; do
        echo "number is $i"
    done

    每5打印一次,即打印5,8,11,14。

    函数

    定义函数如下:

    myfunc() 
    {
        echo "hello world $1"
    }

    或者:

    function myfunc() 
    {
        echo "hello world $1"
    }

    函数调用:

    para1="shouwang"
    myfunc $para1

    返回值 返回值

    通常只支持返回值 5 来获取返回值, 这个可以通过以下方式进行。

    function myfunc() {
        local myresult='some value'
        echo $myresult
    }
    val=$(myfunc)  #val的值为some value

    返回方法适合判断函数执行是否成功

    function myfunc() {
    
        #do something
        return 0
    }
    if myfunc;then
        echo "success"
    else
        echo "failed"
    fi

    注释

    Shell使用#来注释内容行。我们之前见过:

    #!/bin/bash
    # 这是一行注释
    :'
    这是
    多行
    注释
    '
    ls
    :<<eof
    这也可以
    达到
    多行注释
    的目的
    EOF</eof
    

    日志保存

    运行脚本后,不可避免地要记录日志。最常见的方法是重定向。以下面的脚本为例:

    #!/bin/bash
    #test.sh
    lll  #这个命令是没有的,因此会报错
    date

    方法一,将标准输出保存到文件中,并打印标准错误:

    ./test.sh > log.dat

    这种情况下,如果命令执行过程中出现错误,则会将错误打印到控制台。因此,如果您从程序中调用它,则不会记录任何错误消息。

    方法二,标准输出和标准错误保存到日志文件中:

    ./test.sh > log.dat 2>&1

    2>&1 可参考《如何理解linuxshell中的2>&1》

    方法三,保存日志文件时,输出也是到控制台:

    ./test.sh |tee log.dat

    脚本 最常见的执行方式

    我们已经见过:

    ./test.sh

    其他执行方式:

    sh test.sh  #在子进程中执行
    sh -x test.sh #会在终端打印执行到命令,适合调试
    source test.sh #test.sh在父进程中执行
    . test.sh   #不需要赋予执行权限,临时执行

    脚本退出代码

    很多时候我们需要获取脚本执行的结果,即退出位置。通常0表示执行成功。 0位表示失败。要获取退出代码,我们需要使用 exit。例如:

    #!/bin/bash
    function myfun()
    {
        if [ $# -lt 2 ]
        then
           echo "para num error"
           exit 1
        fi
        echo "ok"
        exit 2
    }
    if [ $# -lt 1 ]
    then
       echo "para num error"
        exit 1
    fi
    returnVal=`myfun aa`
    echo "end shell"
    exit 0

    这里需要特别注意的是,当你使用

    returnVal=`myfun aa`

    这样的语句来执行函数时,即使是在exit函数中,也并没有结束脚本的执行,只是退出该函数。这是因为退出意味着退出当前进程,这样执行函数相当于fork子进程,所以当前脚本不会退出。最终结果将被看到,无论你的函数的参数是什么,终端 shell 都会打印它。

    ./test.sh;echo $?
    0

    总结

    以上就是shell编程最基本、最重要的内容。当然,这还不是全部。例如字段、字典、参数处理等就不详细介绍了。由于篇幅有限,将在后续文章中详细介绍。学好shell,放松双手。

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

热门