美文网首页Linux初学者学习笔记
20170824 Shell编程进阶(一)

20170824 Shell编程进阶(一)

作者: 哈喽别样 | 来源:发表于2017-08-27 23:42 被阅读2次
    • 选择执行:if语句
    • 条件判断:case语句
    • 循环控制:for语句
    • 循环控制:while语句和until语句
    • 循环控制:continue, break, shift语句
    • 循环控制:select语句
    • 信号捕捉:trap语句

    一、选择执行:if 语句

    • 单分支
    if 判断条件; then
          判断条件为真的代码
    fi
    
    • 双分支
    if 判断条件; then
          判断条件为真的代码
    else
          判断条件为假的代码
    fi
    
    • 多分支:逐条件判断,直到满足条件执行分支代码,忽略之后的条件判断
    if 判断条件1; then 
          判断条件1为真的代码 
    elif 判断条件2; then
          判断条件2为真的代码
    elif 判断条件3; then
          判断条件3为真的代码
    ... 
    else 
          上述所有条件为假的代码
    fi
    
    • 实验:当运行脚本时已经自带参数,输出参数值;若运行脚本时没有自带参数,则提示输入参数,并输出参数值
    #! /bin/bash
    if [ $# -eq 0 ] ;then
            read -p "please type the words: " words
    else
            words=$*
    fi
    echo $words
    

    二、条件判断:case 语句

    • 语法:
    case 变量引用 in 
    PAT1)
            分支语句1
            ;;
    PAT2)
            分支语句2
            ;;
    PAT3)
            分支语句3
            ;;
    ...
    *)
            默认分支语句
            ;;
    esac
    
    
    • PAT:支持glob通配符
      *:任意长度任意字符
      ?:任意单个字符
      []:指定范围内的任意单个字符
      a|b:a或b

    • 实现一个菜单:

    序号 菜名 价格
    1 lamian 10
    2 huimian 10
    3 yangroutang 20
    4 gaifan 15
    5 jiaozi 20

    要求输入菜名序号后,显示出相应菜品的价格

    #! /bin/bash
    cat <<eof
    menu:
    1) lamian
    2) huimian
    3) yangroutang
    4) gaifan
    5) jiaozi
    eof
    read -p "choose your menu(eg:1): " menu
    case $menu in
    1|2)
            echo "menu $menu price is 10"
            ;;  
    3|5)
            echo "menu $menu price is 20"
            ;;  
    4)
            echo "menu $menu price is 15"
            ;;  
    *)
            echo "wrong menu"
            ;;  
    esac
    

    三、循环控制:for 语句

    • 循环结构的基本组成:初始值、循环开始和结束条件、循环体
    (1)基本用法:
    • 语法:
    for 变量名 in 列表; do
    循环体
    done
    
    • 执行机制:
      依次将列表中的元素赋值给“变量名”; 每次赋值后即执行一次循环体; 直到列表中的元素耗尽,循环结束

    • 列表生成方式:

      • 直接给出列表
      • 整数列表: {start..end}, {start..end...step}
      • 返回列表的命令:$(COMMAND) 或 `COMMAND`,如 $(seq start step end)
      • 使用glob:*.sh
      • 变量引用:$@, $*
    (2)特殊用法(双小括号方法):
    • 双小括号法:用两组括号嵌套(()),可以实现C语言风格变量操作,如
      let i++等同于((i++))

    • for 循环的特殊格式

      • 语法:
    for ((控制变量初始化;条件判断表达式;控制变量的修正表达式)); do
          循环体
    done
    
    • 控制变量初始化:仅当运行到循环代码段开始时执行一次

    • 控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后再做条件判断

    • 实验:建立一个10*10矩阵,每个位置以“行号.列号”方式命名,如第1行第3列的内容为1.3

    #! /bin/bash
    for i in {1..10}; do  
            for j in {1..10}; do
                    echo -ne "$i.$j\t"
            done
            echo
    done
    
    ***另一种实现***
    
    #! /bin/bash
    for ((i=1;i<=10;i++));do 
            for ((j=1;j<=10;j++));do
                    echo -ne "$i.$j\t"
            done
            echo
    done
    
    

    四、循环控制:while 语句和until 语句

    (1)while 语句
    • 语法:
    while CONDITON ; do
          循环体
    done
    
    • CONDITION 循环控制条件
      值为true或false,只有为true时才能执行循环体,一般在循环体中有循环控制变量在每一次循环中变化,最终使CONDITION值由true转变为false,从而终止循环

    • 进入条件:CONDITION=true
      退出条件:CONDITION=false

    • 无限循环:

    while true; do
          COMMANDs
    done
    
    • 特殊用法:遍历文件的每一行
    while read line ; do
          循环体 
    done < /path/to/file     //依次读取/path/to/file文件的每一行,并将行复制给变量line
    
    • 实验:判断/etc/passwd文件每个用户是系统用户还是普通用户(CentOS 7)
    #! /bin/bash
    while read userline; do
            userid=`echo $userline | cut -d: -f3`
            username=`echo $userline | cut -d: -f1`
            if (( userid < 1000 )); then
                    echo "$username is system user"
            else
                    echo "$username is common user"
            fi  
    done < /etc/passwd
    
    (2)until 语句
    • 语法:
    until CONDITION ; do
          循环体
    done
    
    • CONDITION循环控制条件
      值为false时执行循环体,当值为true时,终止循环

    • 进入条件:CONDITION=false
      退出条件:CONDITION=true

    • 无限循环:

    until false; do
          COMMANDs
    done
    

    五、循环控制:continue, break, shift语句

    (1)continue 语句
    • continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断
      最内层为第1层

    • 不写层数默认为第1层

    • 在循环体中使用,语法:

    while CONDITION1; do
          CMD1
          ...
          if CONDITION2; then
                continue     //continue命令表示跳出本轮循环,直接下一轮循环开始判断CONDITION1值
          fi
          CMDn
          ...
    done
    
    • 实验:输出与上文类似的10*10矩阵,但是行号与列号相同的位置为空白
    #! /bin/bash
    for i in {1..10}; do  
            for j in {1..10}; do
                    [ $j -eq $i ] && { echo -ne "\t";continue; }     //行号与列号相同时,输出制表符,跳出本轮循环
                    echo -ne "$i.$j\t"
            done
            echo
    done
    
    (2)break 语句
    • break [N]:提前结束第N层循环
      最内层为第1层

    • 不写层数默认为第1层

    • 在循环体中使用,语法:

    while CONDITION1; do
          CMD1
          ...
          if CONDITION2; then
                break     //continue命令表示跳出本层循环,执行本层循环外的语句
          fi
          CMDn
          ...
    done
    
    • 实验:输出与上文类似的10*10矩阵,但是列号大于等于行号的位置为空白
    #! /bin/bash
    for i in {1..10}; do  
            for j in {1..10}; do
                    [ $j -eq $i ] && break     //行号与列号相同时,终止本层循环,故列号大于行号的位置也没有机会输出
                    echo -ne "$i.$j\t"
            done
            echo
    done
    
    (3)shift 语句
    • 语法:shift [N]

    • 用于将参数列表左移N次,缺省为左移一次

    • 参数列表一旦被移动,最左端的那个参数就从列表中删除

    • while 循环遍历位置参量列表时,常用到shift

    • 实验:
      (1)输入n个参数,第1行输出第1-n个参数,第2行输出第2-n个参数,以此类推,直到第n行输出第n个参数

    #! /bin/bash
    while [ $# -gt 0 ]; do
            echo "$*"
            shift
    done
    

    (2)输入n个参数,每行输出一个参数

    #! /bin/bash
    until [ -z "$1" ];do
            echo "$1"
            shift
    done
    

    六、循环控制:select 语句

    • 语法:
    select variable in list; do
          循环体命令
    done
    
    • select 循环主要用于创建菜单,按数字顺序排列的菜单项将显示在标准错误上,并显示PS3 提示符,等待用户输入

    • 用户输入菜单列表中的某个数字,执行相应的命令

    • 用户输入被保存在内置变量REPLY 中

    • select是个无限循环,因此要记住用break命令退出循环,或用exit命令终止脚本,也可以按ctrl+c退出循环

    • select经常和case联合使用

    • 实验:实现一个菜单,输入菜单编号显示价格,不存在的菜单号显示"wrong menu"并退出

    序号 菜名 价格
    1 lamian 10
    2 huimian 10
    3 yangroutang 20
    4 gaifan 15
    5 jiaozi 20
    #! /bin/bash
    PS3="please type the menu num: "          //环境变量PS3指定提示符格式
    select menu in lamian huimian rangroutang gaifan jiaozi; do
            case $REPLY in          //用户的输入自动存入REPLY变量中
            1)  
                    echo "the price of lamian is \$10"
                    ;;  
            2)  
                    echo "the price of huimian is \$10"
                    ;;  
            3)  
                    echo "the price of rangroutang is \$20"
                    ;;  
            4)  
                    echo "the price of gaifan is \$15"
                    ;;  
            5)  
                    echo "the price of jiaozi is \$20"
                    ;;  
            *)  
                    echo "wrong menu"
                    break          //select语句默认无限循环,需要有break命令退出循环
                    ;;  
            esac
    done
    

    七、信号捕捉:trap 语句

    • trap '触发指令' 信号
      进程收到系统发出的信号后,执行触发指令,而不执行信号操作

    • trap ' ' 信号
      进程收到系统发出的信号后,直接忽略

    • trap '-' 信号
      进程收到系统发出的信号后,恢复信号操作

    *trap -p
    列出自定义信号操作

    • 实验:trap语句验证,以信号2 SIGINT为例
    #! /bin/bash
    trap 'echo "signal:sigint"' sigint     //接到sigint信号输出"signal:sigint"
    trap -p
    for (( i=1;i<=5;i++ )); do
            echo $i
            sleep 2
    done
    trap ' ' sigint                        //接到sigint信号直接忽略
    trap -p
    for (( j=6;j<=10;j++ )); do
            echo $j
            sleep 2
    done
    trap '-' sigint                        //接到sigint信号恢复信号操作
    trap -p
    for (( k=11;k<=15;k++ )); do
            echo $k
            sleep 2
    done
    

    共3个循环,每个循环开始前都输出了相应的自定义信号情况
    输出1-5时,Ctrl+C发出sigint信号后,直接执行替换的命令echo "signal:sigint,循环继续
    输出6-10时,Ctrl+C发出sigint信号后,直接忽略信号,循环继续
    输出11-15时,Ctrl+C发出sigint信号后,恢复信号本身作用,循环被终止

    相关文章

      网友评论

        本文标题:20170824 Shell编程进阶(一)

        本文链接:https://www.haomeiwen.com/subject/yxysdxtx.html