062011
 

第四部分 基础Shell编程

十六、Shell脚本介绍

增加脚本执行权限,用 chmod u+x name.sh

执行脚本,使用 ./name.sh

十七、条件测试

测试一些条件,返回结果储存在 $? 中。测试条件,来实现一些分支判断。

使用test命令,或者[空格 命令 空格]来执行测试
    文件测试的选项有:
        -d 文件夹
        -f 普通文件
        -L 链接文件
        -r 可读
        -w 可写
        -x 可执行
        -s 非空文件
        例如$ [ -w myfirstc.c ]
                $ echo $?
                0
    逻辑连接两个测试:
        -a 与运算,如[ -w file1 -a -w file2 ]
        -o 或运算,如[ -r file1 -o -r file2 ]
        !  非运算,如[ ! -w myfirstc.c ]


    字符串的测试:
        =  字符串相等,如[ "$STR1" = "$STR2" ]。注意,比较两个字符串变量时,必须在变量外加引号。
        != 字符串不等,如[ "good" != "bad" ]
        -z 空串测试,如[ -z $EDITOR ]
        -n 非空串测试,如[ -n $EDITOR ]
    数值测试:
        -eq ==
        -ne =
        -lt <
        -le <=
        -gt >
        -ge >=
        同样的,比较的为数字变量时,要在变量外加上引号,数字也要加引号,如[ "$NUM" -eq "20" ]

expr命令的用法
    命令expr一般用于整数值,也可用于字符串。其一般用法有:
        循环中实现计数,类似i++。
            $ LOOP=0
            $ LOOP= `expr $LOOP + 1`
        测试一个变量是否为数值:
            $ VALUE=12
            $ expr $VALUE + 10 > /dev/null 2>&1
            $ echo $?
            0
            如果$VALUE不是一个数字,则$?返回一个非零的数字。
        用来模式匹配:
            没看懂,暂时略去。

十八、控制流结构

if then else fi 控制

    模式一:
    if [ 测试语句 ] &&或者|| [ 其他测试语句 ]
    then
        执行语句
    elif
        执行语句…
    else
        执行语句
    fi

    模式二:
    if 某shell命令 >/dev/null 2>&1
    then
        执行语句
    else
        执行语句
    fi

    如果if的同一行跟着一个then的话,测试的条件或者shell命令后面要加分号,再加then。
    if [ 语句 ]; then

    一些特殊的:
    if [ -t ]; then 用于测试是否脚本运行于交互模式
    if [ $# -eq "3" ]; then 用于检测传给脚本的参数个数
        echo "`basename $0` : it's right!"
    fi

    null符号: ,即冒号。表示什么也不做,相当于Python中的pass语句。
    if [  -z "`ls -A $DIRNAME`" ]; then
        do something
    else:     #什么也不做
    fi

case 语句控制
    case 值 in
        模式1)
            命令1…
            ;;
        模式2)
            命令2…
            ;;
    esac
模式中,可以使用*, ?, [范围], 模式1|模式2, 

for in do done语句控制
    for 变量名 in 列表
    do
        命令1
        命令2
    done
    一些简单例子
        for loop in 1 2 3 4
        for loop in "orange potato apple"
        for i in `ls`
    使用参数
        for param in "$@"
        for param in "$*"
    变量计数实现i++
        counter=0   #必须初始化!
        for filename in `ls`
        do
            counter=`expr $counter + 1`
        done
        echo "Total number of the files is $counter"

while以及until循环

    while 或 until [ 测试语句 ]
    do
        命令…
    done

    一个until的例子,监控root用户的登录
    #! /bin/sh
    IS_ROOT=`who | grep root`
    until [ "$IS_ROOT" ]
    do
        sleep 5
    done
    echo "it's the root"
    这里虽然IS_ROOT是在循环体外定义执行的,但是每次循环还是会执行并更改它的值?只是猜测。

    while read NAME DEPT SALARY
    do
        echo "$NAME\t$DEPT\t$SALARY"
    done

    如何实现c中的while(1)循环
        while :    #注意null符号“:”的使用,使这个while成为一个死循环

break和continue
    break 跳出最内层的整个循环
    continue 跳过本步循环,开始下一步,并不跳出循环

再次提到如何输出文本块,类似Python中的'''符号,使用:
    cat <<SOMETHING
    blah blah
    wahaha
    SOMETHING

十九、Shell中使用函数

定义函数,使用:
    function 函数名()
    {
        …
    }

向函数传递参数:
    还是使用$0…$9这样,最好复制到函数内的一个变量,避免意外更改参数并更有意义。

返回值
    return
    return 0 #无出错返回
    return 1 #有出错返回

在调用者用测试返回值,使用:
    foo $VAR
    if [ $? -eq "0" ]; then
    或者
    if foo $VAR; then

创建函数文件
    在开头加入 #! /bin/sh
    写入各种函数

包含函数和常量
    使用时,在调用者的开头写上这个函数文件的名称即可包含其中的函数,以及常量

删除函数
    使用unset func_name

二十、向脚本传递参数

使用shift命令
    从参数列表的最左端取得$1参数,然后shift,即可使参数列表左移一个位置,原来的$2变为$1。这样的好处是在一个循环之中只要不断处理$1的值,即可获得整个参数列表。
        while [ $# -ne 0 ]
        do
            echo $1
            shift
        done
    特别地,使用shift `expr $# -2`可以获得最后一个参数。

使用getopts命令获得参数
    getopts函数将输入脚本的,带有-的参数看作是选项,并进行处理:
    while getopts aghv OPTION
    do
        case $OPTION in
            a) echo "a"
            ;;
            g) echo "g"
            ;;
            h) echo "h"
            ;;
            v) echo "v"
            ;;
        esac
    done
    使用形如 getopts :aghv: OPTION 的方式,可以强制要求给 -v 选项传递一个值。
        如果不给它赋值,那么在case语句里面增加如下一项:
            \?) echo "-v 必须赋值"
        这样,如果调用者未给-v赋值,则会报错,提示信息就是上面的字符串。
    传进来的值,使用变量$OPTARG来访问。

一个较完整的例子:
    #! /bin/sh
    # backups
    QUIET=n
    DEVICE=awa
    LOGFILE=/tmp/logbackup
    usage()
    {
        echo "Usage: `basename $0` -d [device] -l [logfile] -q"
        exit 1
    }
    if [ $# -eq 0 ]
    then
        usage
    fi
    
    while getopts :ql:d: OPTION
    do
        case $OPTION in
        q) QUIET=y
            LOGFILE="/tmp/backup.log"
            ;;
        d) DEVICE=$OPTARG
            ;;
        l) LOGFILE=$OPTARG
            ;;
        \?) usage
            ;;
        esac
    done
    echo "Your choices are"
    echo "QUIET= $QIUET $DEVICE $LOGFILE"

对于选项的字母,还有一些命名的约定俗成的方式,可以查询相关的内容。

二十一、创建屏幕输出

使用tput命令
    首先,tput init 初始化一下
    字符串输出:
    
    数字输出:
    
        cols  列数
    
        it    tab宽度
    
        lines 屏幕行数
    布尔输出:
    
        chts  光标不可见
    
        hs    具有状态行

二十二、创建屏幕输入

    一句话,对于用户输入的各种验证

二十三、调试脚本

    set -x 打开,在脚本的每行输出都显示命令及其参数
    set +x 关闭
    
    添加大量echo语句跟踪执行过程

二十四、Shell的嵌入命令

    
    set命令,在脚本内部使用
    
    set arg1 arg2
    这样的指令。相当于从外部调用者传入了arg1和arg2两个参数。

    type 检查一个命令是否存在,存在的话给出其位置。

    wait 使用
        wait pid
    等待指定pid的进程结束,再执行下一条指令。单一个wait表示等待所有子进程运行完毕。


 Leave a Reply

(必须填写)

(必须填写,邮件地址不会被泄露)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>