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解释器首次发现它时,才可以使用。调用函数仅使用其函数名即可。

  • 相关阅读:
    hdu 1199 Color the Ball 离散线段树
    poj 2623 Sequence Median 堆的灵活运用
    hdu 2251 Dungeon Master bfs
    HDU 1166 敌兵布阵 线段树
    UVALive 4426 Blast the Enemy! 计算几何求重心
    UVALive 4425 Another Brick in the Wall 暴力
    UVALive 4423 String LD 暴力
    UVALive 4872 Underground Cables 最小生成树
    UVALive 4870 Roller Coaster 01背包
    UVALive 4869 Profits DP
  • 原文地址:https://www.cnblogs.com/new0801/p/6177027.html
Copyright © 2011-2022 走看看