zoukankan      html  css  js  c++  java
  • Linux系统编程(15)——shell脚本语法

    Shell字符串

    字符串是shell编程中最常用最有用的数据类型(除了数字和字符串,也没啥其它类型好用了),字符串可以用单引号,也可以用双引号,也可以不用引号。单双引号的区别跟PHP类似。

    单引号

    str='this is a string'

    单引号字符串的限制:

    单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;

    单引号字串中不能出现单引号(对单引号使用转义符后也不行)。

    双引号

    your_name='qinjx'
    str="Hello, I know your are"$your_name"! 
    "


    双引号的优点:

    双引号里可以有变量

    双引号里可以出现转义字符


    拼接字符串 

    your_name="qinjx"
    greeting="hello,"$your_name" !"
    greeting_1="hello, ${your_name}!"
    echo $greeting $greeting_1


    获取字符串长度

    string="abcd"
    echo ${#string} #输出 4


    提取子字符串

    string="alibaba is a greatcompany"
    echo ${string:1:4} #输出liba


    查找子字符串

    string="alibaba is a greatcompany"
    echo `expr index "$string" is`


    Shell数组

    Linux Shell在编程方面比Windows批处理强大很多,无论是在循环、运算。

    bash支持一维数组(不支持多维数组),并且没有限定数组的大小。类似与C语言,数组元素的下标由0开始编号。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于0。

    定义数组

    在Shell中,用括号来表示数组,数组元素用“空格”符号分割开。定义数组的一般形式为:

        数组名=(值1 值2 ... 值n)

    例如:

    array_name=(value0 value1 value2 value3)


    或者

    array_name=(
    value0
    value1
    value2
    value3
    )


    还可以单独定义数组的各个分量:

    array_name[0]=value0
    array_name[1]=value1
    array_name[n]=valuen


    可以不使用连续的下标,而且下标的范围没有限制。

    读取数组

    读取数组元素值的一般格式是:

       ${数组名[下标]}


    例如:

    valuen=${array_name[n]}


    使用@符号可以获取数组中的所有元素,例如:

    echo ${array_name[@]}


    获取数组的长度

    获取数组长度的方法与获取字符串长度的方法相同,例如:

    # 取得数组元素的个数
    length=${#array_name[@]}
    # 或者
    length=${#array_name[*]}
    # 取得数组单个元素的长度
    lengthn=${#array_name[n]}

    Shelltest命令

    Shell中的 test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试。

    数值测试

    参数

    说明

    -eq

    等于则为真

    -ne

    不等于则为真

    -gt

    大于则为真

    -ge

    大于等于则为真

    -lt

    小于则为真

    -le

    小于等于则为真

    例如:

    num1=100
    num2=100
    if test $[num1] -eq $[num2]
    then
       echo 'The two numbers are equal!'
    else
       echo 'The two numbers are not equal!'
    fi


    输出:

    The two numbers are equal!

    字符串测试

     

    参数

    说明

    =

    等于则为真

    !=

    不相等则为真

    -z 字符串

    字符串长度伪则为真

    -n 字符串

    字符串长度不伪则为真

    例如:

    num1=100
    num2=100
    if test num1=num2
    then
       echo 'The two strings are equal!'
    else
       echo 'The two strings are not equal!'
    fi


    输出:

    The two strings are equal!

    文件测试

     

    参数

    说明

    -e 文件名

    如果文件存在则为真

    -r 文件名

    如果文件存在且可读则为真

    -w 文件名

    如果文件存在且可写则为真

    -x 文件名

    如果文件存在且可执行则为真

    -s 文件名

    如果文件存在且至少有一个字符则为真

    -d 文件名

    如果文件存在且为目录则为真

    -f 文件名

    如果文件存在且为普通文件则为真

    -c 文件名

    如果文件存在且为字符型特殊文件则为真

    -b 文件名

    如果文件存在且为块特殊文件则为真

    例如:

    cd /bin
    if test -e ./bash
    then
       echo 'The file already exists!'
    else
       echo 'The file does not exists!'
    fi


    输出:

    The file already exists!

    另外,Shell还提供了与( ! )、或( -o )、非( -a )三个逻辑操作符用于将测试条件连接起来,其优先级为:“!”最高,“-a”次之,“-o”最低。例如:

    cd /bin
    if test -e ./notFile -o ./bash
    then
       echo 'One file exists at least!'
    else
       echo 'Both dose not exists!'
    fi


    输出:

    One file exists at least!

    条件判断语句if/then/elif/else/fi

    和C语言类似,在Shell中用if、then、elif、else、fi这几条命令实现分支控制。这种流程控制语句本质上也是由若干条Shell命令组成的,例如先前讲过的

    if [ -f ~/.bashrc ]; then

        .~/.bashrc

    fi其实是三条命令,if [ -f~/.bashrc ]是第一条,then . ~/.bashrc是第二条,fi是第三条。如果两条命令写在同一行则需要用;号隔开,一行只写一条命令就不需要写;号了,另外,then后面有换行,但这条命令没写完,Shell会自动续行,把下一行接在then后面当作一条命令处理。和[命令一样,要注意命令和各参数之间必须用空格隔开。if命令的参数组成一条子命令,如果该子命令的Exit Status为0(表示真),则执行then后面的子命令,如果Exit Status非0(表示假),则执行elif、else或者fi后面的子命令。if后面的子命令通常是测试命令,但也可以是其它命令。Shell脚本没有{}括号,所以用fi表示if语句块的结束。见下例:

    #! /bin/sh
     
    if [ -f /bin/bash ]
    then echo "/bin/bash is a file"
    else echo "/bin/bash is NOT afile"
    fi
    if :; then echo "always true";


    fi:是一个特殊的命令,称为空命令,该命令不做任何事,但Exit Status总是真。此外,也可以执行/bin/true或/bin/false得到真或假的Exit Status。再看一个例子:

    #! /bin/sh
     
    echo "Is it morning? Please answer yesor no."
    read YES_OR_NO
    if [ "$YES_OR_NO" ="yes" ]; then
     echo "Good morning!"
    elif [ "$YES_OR_NO" ="no" ]; then
     echo "Good afternoon!"
    else
     echo "Sorry, $YES_OR_NO not recognized. Enter yes or no."
     exit 1
    fi
    exit 0

    上例中的read命令的作用是等待用户输入一行字符串,将该字符串存到一个Shell变量中。

    此外,Shell还提供了&&和||语法,和C语言类似,具有Short-circuit特性,很多Shell脚本喜欢写成这样:

    test "$(whoami)" != 'root'&& (echo you are using a non-privileged account; exit 1)

    &&相当于“if...then...”,而||相当于“ifnot...then...”。&&和||用于连接两个命令,而上面讲的-a和-o仅用于在测试表达式中连接两个测试条件,要注意它们的区别,例如,

    test "$VAR" -gt 1 -a"$VAR" -lt 3


    和以下写法是等价的

    test "$VAR" -gt 1 && test"$VAR" -lt

    case/esac语句

    case命令可类比C语言的switch/case语句,esac表示case语句块的结束。C语言的case只能匹配整型或字符型常量表达式,而Shell脚本的case可以匹配字符串和Wildcard,每个匹配分支可以有若干条命令,末尾必须以;;结束,执行时找到第一个匹配的分支并执行相应的命令,然后直接跳到esac之后,不需要像C语言一样用break跳出。

    #! /bin/sh
     
    echo "Is it morning? Please answer yesor no."
    read YES_OR_NO
    case "$YES_OR_NO" in
    yes|y|Yes|YES)
     echo "Good Morning!";;
    [nN]*)
     echo "Good Afternoon!";;
    *)
     echo "Sorry, $YES_OR_NO not recognized. Enter yes or no."
     exit 1;;
    esac
    exit 0


    使用case语句的例子可以在系统服务的脚本目录/etc/init.d中找到。这个目录下的脚本大多具有这种形式(以/etc/apache2为例):

    case $1 in
             start)
                       ...
             ;;
             stop)
                       ...
             ;;
             reload| force-reload)
                       ...
             ;;
             restart)
             ...
             *)
                       log_success_msg"Usage: /etc/init.d/apache2{start|stop|restart|reload|force-reload|start-htcacheclean|stop-htcacheclean}"
                       exit1
             ;;
    esac启动apache2服务的命令是
     
    $ sudo /etc/init.d/apache2

     

    start$1是一个特殊变量,在执行脚本时自动取值为第一个命令行参数,也就是start,所以进入start)分支执行相关的命令。同理,命令行参数指定为stop、reload或restart可以进入其它分支执行停止服务、重新加载配置文件或重新启动服务的相关命令。

    for/do/done语句

    Shell脚本的for循环结构和C语言很不一样,它类似于某些编程语言的foreach循环。例如:

    #! /bin/sh
     
    for FRUIT in apple banana pear; do
     echo "I like $FRUIT"
    done

    FRUIT是一个循环变量,第一次循环$FRUIT的取值是apple,第二次取值是banana,第三次取值是pear。再比如,要将当前目录下的chap0、chap1、chap2等文件名改为chap0~、chap1~、chap2~等(按惯例,末尾有~字符的文件名表示临时文件),这个命令可以这样写:

    $ for FILENAME in chap?; do mv $FILENAME$FILENAME~; done



    也可以这样写:

    $ for FILENAME in `ls chap?`; do mv $FILENAME$FILENAME~; done5.5. while/do/done


    while的用法和C语言类似。比如一个验证密码的脚本:

    #! /bin/sh
     
    echo "Enter password:"
    read TRY
    while [ "$TRY" !="secret" ]; do
     echo "Sorry, try again"
     read TRY
    done

    下面的例子通过算术运算控制循环的次数:

     
    #! /bin/sh
     
    COUNTER=1
    while [ "$COUNTER" -lt 10 ]; do
     echo "Here we go again"
     COUNTER=$(($COUNTER+1))
    Done


    Shell还有until循环,类似C语言的do...while循环。

    Shell函数

    shell允许将一组命令集或语句形成一个可用块,这些块称为shell函数。

    shell中函数的定义格式如下:

    函数名(){
       command1
       command2
       ...
       commandN
        [return value ]
    }


     如果愿意,可在函数名前加上关键字function,这取决于使用者。

    function 函数名(){
       command1
       command2
       ...
       commandN
        [return value ]
    }


    函数返回值,可以显示增加return语句;如果不加,则将最后一条命令运行结果作为返回值(一般为0,如果执行失败则返回错误代码)。 return后跟数值(0-255)。

    函数可以放在同一个文件中作为一段代码,也可以放在只包含函数的单独文件中。函数不必包含很多语句或命令,甚至可以只包含一个echo语句,这取决于使用者。

    下面的例子定义了一个函数并进行调用:

    #!/bin/bash
    demoFun(){
       echo "This is your first shell function!"
    }
    echo "Function begin..."
    hello
    echo "Function end!"


    输出:

    Function begin...

    This is your first shell function!

    Function end!

    下面定义一个带有return语句的函数:

    #!/bin/bash
    funWithReturn(){
       echo "The function is to get the sum of two numbers..."
       echo -n "Input first number: "
       read aNum
       echo -n "Input another number: "
       read anotherNum
       echo "The two numbers are $aNum and $anotherNum !"
       return $(($aNum+$anotherNum))
    }
    funWithReturn
    echo "The sum of two numbers is $?!"


    输出类似下面:

    The function is to get the sum of twonumbers...

    Input first number: 25

    Input another number: 50

    The two numbers are 25 and 50 !

    The sum of two numbers is 75 !

    函数返回值在调用该函数后通过 $? 来获得。

    注意:所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,直至shell解释器首次发现它时,才可以使用。调用函数仅使用其函数名即可。

  • 相关阅读:
    WebService到底是什么?(转)
    C# 页面抓取获取快递信息
    SQL Server ->> 条件筛选做法之 -- IN(VALUE1,VALUE2,...)与INNER JOIN STRING_SPLIT()性能对比
    SQL Server ->> MSDB.DBO.AGENT_DATETIME函数从整型转时间日期格式
    Windows ->> Windows Server 2012打开管理添加“我的电脑”桌面图标途径
    Windows ->> Windows下安装MSI程序遇到2503和2502错误
    SQL Server ->> DAC(Dedicated Administrator Connection)专用管理员连接
    SQL Server ->> 高可用与灾难恢复(HADR)技术之 -- Transaction Replication(事务复制)
    SQL Server ->> ColumnStore Index(列存储索引)
    SQL Server ->> 使用Azure Active Directory Authentication连接到Azure SQL Database
  • 原文地址:https://www.cnblogs.com/new0801/p/6177027.html
Copyright © 2011-2022 走看看