第一部分:Linux命令行
    《Linux命令行与shell脚本编程大全》 第一章:初识Linux shell
    《Linux命令行与shell脚本编程大全》 第二章:走进shell
    《Linux命令行与shell脚本编程大全》 第三章:基本的bash shell命令
    《Linux命令行与shell脚本编程大全》 第四章:更多的bash shell命令
    《Linux命令行与shell脚本编程大全》 第五章:使用Linux环境变量
    《Linux命令行与shell脚本编程大全》 第六章:理解Linux文件权限
    《Linux命令行与shell脚本编程大全》 第七章:管理文件系统
    《Linux命令行与shell脚本编程大全》 第八章:安装软件程序
    《Linux命令行与shell脚本编程大全》 第九章:使用编辑器

    第二部分:shell脚本编程基础
    《Linux命令行与shell脚本编程大全》 第十章:构建基本脚本
    《Linux命令行与shell脚本编程大全》 第十一章:使用结构化命令
    《Linux命令行与shell脚本编程大全》 第十二章:更多的结构化命令
    《Linux命令行与shell脚本编程大全》 第十三章:处理用户输入
    《Linux命令行与shell脚本编程大全》 第十四章:呈现数据
    《Linux命令行与shell脚本编程大全》 第十五章:控制脚本

    第三部分:高级shell编程
    《Linux命令行与shell脚本编程大全》 第十六章:创建函数
    《Linux命令行与shell脚本编程大全》 第十七章:图形化桌面上的脚本编程
    《Linux命令行与shell脚本编程大全》 第十八章:初识sed和gawk
    《Linux命令行与shell脚本编程大全》 第十九章:正则表达式
    《Linux命令行与shell脚本编程大全》 第二十章:sed进阶
    《Linux命令行与shell脚本编程大全》 第二十一章:gawk进阶
    《Linux命令行与shell脚本编程大全》 第二十二章:使用其他shell

    第四部分:高级shell脚本编程主题
    《Linux命令行与shell脚本编程大全》 第二十三章:使用数据库
    《Linux命令行与shell脚本编程大全》 第二十四章:使用Web
    《Linux命令行与shell脚本编程大全》 第二十五章:使用E-mail
    《Linux命令行与shell脚本编程大全》 第二十六章:编写脚本实用工具
    《Linux命令行与shell脚本编程大全》 第二十七章:shell脚本编程进阶


    第十三章:处理用户输入

    命令行参数
    读取参数
    bash shell会将一些称为位置参数(positional parameter)的特殊变量分配给命令行输入的所有参数
    甚至包括程序名
    $0 :程序名( 程序的绝对路径 ), 可以对$0使用basename函数(basename $0) ,它只返回程序名
    $i(9>i>0) :第i个参数
    如果需要的参数多于9个,那么只需${10} ,这样既可
    如果脚本需要参数,但是执行的时候并没有输入参数,执行的时候则会得到错误

       if [ -n "$1" ]
    ……
      
    应该先检查是否有参数,然后再做处理

    特殊参数变量
    $# :参数数量
    ${!#} :最后一个参数。 花括号({})中不允许使用美元符号($) 这里使用感叹号(!)

    所以下面的代码是错误的

       #!/bin/bash
    echo We have "$#" "parameter(s)"
    echo The last parameter is "${$#}" # wrong way
    echo The last parameter is "${!#}" # right way
      

    执行结果:

       $ param_test 1 1 1 5
    We have 4 parameter(s)
    The last parameter is 1535
    The last parameter is 5
      

    注意: 当命令行没有任何参数时,$#返回0,而${!#}返回函数名

    提取命令行上的所有参数
    $*
    将命令行上提供的所有参数当做1个单词保存
    $@
    所有参数的集合

       #!/bin/bash
    echo "\$* and \$@ test"
    echo "\$* is:"$* #这里两个输出结果是一样的
    echo "\$@ is:"$@ #
    count=0
    for var in "$*"
    do
        count=$[$count+1]
        echo "$count:"$var
    done
    
    echo "\$* done."
    
    count=0
    for var in "$@"
    do
        count=$[$count+1]
        echo "$count:"$var
    done
    echo "\$@ done."
      
    输出结果:

       $* and $@ test
    $* is:a b c
    $@ is:a b c
    1:a b c
    $* done.
    1:a
    2:b
    3:c
    $@ done.
      



    移动数据
    shift

    将每个变量的位置都提前一个,$0不变,$1被移除。

       count=1
    while [ -n "$1" ]
    do
        echo "Paramter #$count=$1"
        count=$[$count + 1]
        shift
    done
      

    注意:当参数被移除之后,无法恢复。

    处理选项

       while [-n $1 ]
    do
        case "$1" in
        -a) echo "Found the -a option" ;;
        -b) echo "Found the -b option" ;;
        *) echo "$1 is not a option" ;;
        esac
        shift
    done
      

    分离参数和选项

    Linux利用双破折线(--)表明选项结束。

       #!/bin/bash
    while [ -n "$1" ]
    do
        case "$1" in
        -a) echo "Found option a";;
        -b) echo "Found option b";;
        --) shift
             break;;#跳出while,而不是case
        *) echo "$1 not a option";;
        esac
        shift
    done
    
    for p in $@
    do
        echo "$p is a param ."
    done
      

    处理带值的选项
       #!/bin/bash
    while [ -n "$1" ]
    do
        case "$1" in
        -a) echo "option a" ;;
        -b) echo "option b. $2 is a param." #如果找到选项b,那么此时$2就应该是选项b的值
            shift;; #p281页,原文为shift 2,实际不需要,因为并没有break出循环
        --) shift
             break;;
        -c) echo "option c" ;;
        *) echo "$1 is not a option. ";;
        esac
        shift
    done
      
    getopt
    语法:
    getopt options optstring parameters
    optstring 中列出所有选项,带值选项要在字母后加冒号(:),如果参数中包含无效参数,那么会给出错误信息
       $ getopt ab:cd -a -b pb -cde p1 p2
    getopt: invalid option -- 'e'
     -a -b pb -c -d -- p1 p2
      
    -q :屏蔽错误报告
       $ getopt -q ab:cd -a -b pb -cde p1 p2
     -a -b 'pb' -c -d -- 'p1' 'p2'
      

    set -- command :set会将命令行参数替换为set命令行的值。
    set -- `getopt ab:cd "$@"`
    getopt将参数格式化好了之后,由set替换掉命令行原始参数。
    将下面脚本保存到文件 getopt_test中
       #!/bin/bash
    set -- `getopt a:b:c "$@"`
    
    echo "param = $@"
    
    while [ -n "$1" ]
    do
        case "$1" in 
         -a) echo "found option a and param = $2" 
             shift ;;
         -b) echo "found option b and param = $2"
             shift ;;
         -c) echo "found option c, no param." ;;
         --) ;;
         *) echo "what's this?" 
            break ;;
        esac
        shift
    done
      
    下面是运行结果
       $ getopt_test -a test -b test -e
    getopt: invalid option -- 'e'
    param = -a test -b test --
    found option a and param = test
    found option b and param = test
      
    可以看出, getopt 可以识别出未知选项
    但是,它还是有些不足
    下面是一个没有正确提供选项的例子
       $ getopt_test -a -b -c
    param = -a -b -c --
    found option a and param = -b
    found option c, no param.
      
    这里将-b识别为-a的参数了,当然这是因为用户输入不正确导致的。但是getopt并没有正确的识别出来
    再看一个参数中含有空格的例子
       $ getopt_test -a "x y"
    param = -a x y --
    found option a and param = x
    what's this?
      
    显然这里getopt错把"x y"当成了两个参数/选项
    最后一个问题,我们可以用下面的命令解决
    getopts
    语法:
    getopts optstring variable
    getopts用到的两个环境变量
    OPTARG :如果选项需要跟着有一个参数值,那么此变量就保存这个参数值
    OPTIND :保存getopts正在处理的参数的位置
    注意:如果想屏蔽错误消息,需要在optstring前面加冒号,而不是使用-q
    getopts将当前参数保存在命令行中定义的 variable
    每调用一次getopts,它只处理命令行中的一个参数,处理完所有参数后,它会退出并返回一个大于0的退出状态码
       #!/bin/bash
    while getopts abc:d opt
    do
        case $opt in
        a) echo "option -a found";;
        b) echo "option -b found";;
        c) echo "option -c found and param = $OPTARG";;
        d) echo "option -d found";;
        ?) p=$[$OPTIND-1]
            echo "what's this? "${!p}
            echo "what's this? "$opt;;
        esac
    done
      
    这里与getopt不同,getopts会自动移出“-”,所以case中就不要加“-”了
    输出结果
       $ param_test -a -b -c "a param" -d -e
    option -a found
    option -b found
    option -c found and param = a param
    option -d found
    ./param_test: illegal option -- e
    what's this? -e
    what's this? ?
      
    getopts将不认识的选项一律以问号输出,所以最后一行我们会多看到一个问号
    将选项标准化
    下面是一些命令中选项的常用的含义(原文为通用,其实并不是很通用)
    选项 描述
    -a 显示所有对象
    -c 生成一个计数
    -d 指定一个目录
    -e 扩展一个对象
    -f 指定读取数据的文件
    -h 显示命令的帮助信息
    -i 忽略文本大小写
    -l 产生输出的长格式版本
    -n 使用非交互模式(批量)
    -o 指定将所有输出重定向到的输出文件
    -q 以安静模式运行
    -r 递归处理目录和文件
    -s 以安静模式运行
    -v 生成详细输出
    -x 排除某个对象
    -y 对所有问题回答yes
    获得用户输入
    read:接受从标准输入(键盘)或另一个文件描述符的输入
    在收到输入后,read命令会将数据放进一个标准变量
       #!/bin/bash
    echo -n "Enter your name:"
    read name
    echo "Hello $name"
    read -p "Enter your age:" age
    echo "You are $age years old..."
      
    echo的-n选项会移除末尾的换行
    -p 可以指定提示语句
    可以将输入保存到多个变量中,如果变量表中变量不够用,之后的输入将都保存到最后一个变量中
       read -p "What would you like to eat?" f1 f2
    echo "you would like to eat $f1 and $f2"
      
    如果不给read指定变量,那么read到的内容将保存到 REPLY 环境变量中
    -t: 指定超时时间,单位为秒
    超时之后,read会返回一个非0的退出状态码
       #!/bin/bash
    read -n1 -p "Are you a boy?" answer
    echo
    case $answer in
    y|Y) echo "Oh, you're a boy.";;
    N|n) echo "Oh, you are not a boy.";;
    esac
      
    -n number 当输入达到number个字符的时候,read结束,并将结果赋给变量
    上面示例中,当输入了一个字符后,程序将自动运行,不需要用户输入回车确定
    -s :隐藏方式读取(其实是将文字颜色设置为背景色而已)
       #!/bin/bash
    while read -n1 -s c
    do
        echo -n "*"
    done
      
    输入的字符以*替代,当然,上面的例子中,如果输入退格键,*号是不会删除,依然继续增加……
    从文件中读取
    read将一次读取文件中的一行,当读取完毕的时候,read会退出并返回非0状态码
       #!/bin/bash
    count=0
    while read line
    do
        count=$[ $count + 1 ]
    done < $1
    echo "$count line(s) in all."
      
    如果用管道给read传送数据,将会开启一个子shell,这样在while外再查看$count,会发现它依然为0

    转贴请保留以下链接

    本人blog地址

    http://su1216.iteye.com/

    http://blog.csdn.net/su1216/