shell高级编程

  • 条件选择if语句
        选择执行: 注意:if语句可嵌套
        单分支
        if 判断条件;then
        条件为真的分支代码
        fi
    
        双分支
        if 判断条件; then
        条件为真的分支代码
        else条件为假的分支代码
        fi
    
        多分支
        if 判断条件1; then
        条件为真的分支代码
        elif 判断条件2; then
        条件为真的分支代码
        elif 判断条件3; then
        条件为真的分支代码
        else以上条件都为假的分支代码
        fi
        逐个条件进行判断,第一次遇为“真”条件时,执行其分支,而后结束整个if语
        句
  • If示例
    根据命令的退出状态来执行命令

    if ping -c1 -W2 station1 &> /dev/null; then
    echo ‘Station1 is UP‘
    elif grep "station1" ~/maintenance.txt &> /dev/null
    then
    echo ‘Station1 is undergoing maintenance‘
    else echo ‘Station1 is unexpectedly DOWN!‘ exit 1
    fi

            条件判断:case语句
    
            case 变量引用 in
            PAT1)
                         分支1
                            ;;
            PAT2)
                            分支2
            ;;
                     ...*)
            默认分支
            ;;
            esac
    
            case支持glob风格的通配符:
            *: 任意长度任意字符
            ?: 任意单个字符
            []:指定范围内的任意单个字符
            a|b: a或b
    • for循环

           for 变量名 in 列表;do
          循环体
          done
          执行机制:
          依次将列表中的元素赋值给“变量名”; 每次赋值后即执行一次循环体; 直到列表中的元素
          耗尽,循环结束

    列表生成方式:

    (1) 直接给出列表
    (2) 整数列表:
    (a) {start..end}
    (b) $(seq [start [step]] end)
    (3) 返回列表的命令$(COMMAND)
    (4) 使用glob,如:.sh
    (5) 变量引用;[email protected], $

    • while循环

          while CONDITION; do
          循环体
          done
          CONDITION:循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次判断;条件
          为“true”,则执行一次循环;直到条件测试状态为“false”终止循环
          因此:CONDTION一般应该有循环控制变量;而此变量的值会在循环体不断地被修正
          进入条件:CONDITION为true
          退出条件:CONDITION为false
    • until循环
      until CONDITION; do
      循环体
      done
      进入条件: CONDITION 为false
      退出条件: CONDITION 为true
          循环控制语句continue
          用于循环体中
          continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断;最内层为第1层
          while CONDTIITON1; do
          CMD1
          ...
          if CONDITION2; then
          continue
          fi
          CMDn
          ...
          done
      
          循环控制语句break
          用于循环体中
          break [N]:提前结束第N层循环,最内层为第1层
          while CONDTIITON1; do
          CMD1...if CONDITION2; then
          breakfiCMDn...done

    示例:doit.sh

            #!/bin/bash
             Name: doit.sh
            Purpose: shift through command line arguments
            Usage: doit.sh [args]
            while [ $# -gt 0 ] # or (( $# > 0 ))
            doecho $*
            shiftdone

    示例:shift.sh

            #!/bin/bash
            #step through all the positional parameters
            until [ -z "$1" ]
            doecho "$1"
            shiftdoneecho
    
            创建无限循环
            while true; do
            循环体
            done 
    
            until false; do
            循环体
            Done
    
        特殊用法
        while循环的特殊用法(遍历文件的每一行):
        while read line; do
        循环体
        done < /PATH/FROM/SOMEFILE
        依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量line

    练习
    扫描/etc/passwd文件每一行,如发现GECOS字段为空,则填充用户名和单位电话为62985600,并提示该
    用户的GECOS信息修改成功。

             #!/bin/bash
             while read line ;do
                             gecos=$(echo $line |cut -d: -f5)
                             if [ -z "$gecos" ];then
                                             UserName=$(echo $line |cut -d: -f1)
                                             usermod -c "$UserName 62985600" $UserName
                                             echo "$UserName‘s gecos changed"
                             fi
             done < /etc/passwd

    编写个脚本,会对系统中已存在的用户进行身份判断,若为centos7,则uid大于1000的用户将判断为comm user,反之判定为sys user, 若为centos6,则uid大于500的用户判断为comm user,反之sys user.输出格式如下
    root: sys user
    ……
    liubei: comm user

             #!/bin/bash
             release=$(cat /etc/centos-release| sed -r ‘s/.* ([0-9]+)..*/\1/‘)
             while read line; do
                     uid=$(echo $line | cut -d: -f3)
                     name=$(echo $line | cut -d: -f1)
                     if [ $release = 6 -a $uid -lt 500 ] || [ $release = 7 -a $uid -lt 1000 ]; then
                             echo "$name: sys user"
                     else
                             echo "$name: comm user"
                     fi
             done < /etc/passwd

    找出分区利用率大于10%的分区,显示结果如下:
    /dev/sda1 will be full : 33%
    /dev/sda2 will be full : 99%

             #!/bin/bash
             df |grep /dev/sd |while read line;do
                             used=$(echo $line |tr -s " " % |cut -d% -f5)
                             name=$(echo $line |cut -d" " -f1)
                             if (( $used > 10 ));then
                                             echo "$name will be full:$used%"
                            fi
             done
    • 特殊用法

          双小括号方法,即((…))格式,也可以用于算术运算
          双小括号方法也可以使bash Shell实现C语言风格的变量操作
          I=10((I++))
          for循环的特殊格式:
          for ((控制变量初始化;条件判断表达式;控制变量的修正表达式))
          do循环体
          done控制变量初始化:仅在运行到循环代码段时执行一次
          控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后再做条件判断
      
          for ((i=1;i<=100;i++));do
                          let sum+=i
          done
          echo sum=$sum
      
          select循环与菜单
          select variable in list
          do
          循环体命令
          done
          select 循环主要用于创建菜单,按数字顺序排列的菜单项将显示在标准错误上,并显示 PS3 提示符,等待用户输入
          用户输入菜单列表中的某个数字,执行相应的命令
          用户输入被保存在内置变量 REPLY 中[][][]
      
          select 是个无限循环,因此要记住用 break 命令退出循环,或用 exit 命令终止脚本。也可以按
          ctrl+c 退出循环
          select 经常和 case 联合使用
          与 for 循环类似,可以省略 in list,此时使用位置参量

    练习:为某餐馆用Shell制作一个点菜系统。
    执行脚本,会列出主菜单,如下
    请问吃什么?
    1) 饭
    2) 面
    3)饺子
    4)不吃

    等待用户选择
    如选择1,则再问,选择完后报价
    1) 炒饭
    2)盖饭
    3)木桶饭
    如选择2,则再问
    1)炒面
    2)盖面
    3)拉面
    4)拌面
    如选择3,则再问
    1)猪肉大葱
    2)素三鲜
    3)韭菜鸡蛋
    每项选择后,最终会报价,如
    木桶饭: 10元
    如选择4,则退出

            #!/bin/bash
            PS3="Please choose your food: "
            echo "请问吃什么"
            caidan() {
            select menu in 饭 面 饺子 不吃;do
                    case $REPLY in
                            1)     select fan in 炒饭 盖饭 木桶饭 返回;do
                                            case $REPLY in
                                                    1) echo "炒饭: 10";break 2;;
                                                    2) echo "盖饭: 12";break 2;;
                                                    3) echo "木桶饭:15";break 2;;
                                                    4) caidan;;
                                            esac
                                    done
                            ;;
                            2)     select mian in 炒面 盖面 拉面 拌面 返回;do
                                            case $REPLY in
                                                    1) echo "炒面: 10";break 2;;
                                                    2) echo "盖面: 12";break 2;;
                                                    3) echo "拉面:15";break 2;;
                                                    4) echo "拌面: 18";break 2;;
                                                    5) caidan;;
                                            esac
                                    done
                            ;;
                            3)    select jiaozi in 猪肉大葱 素三鲜 韭菜鸡蛋 返回;do
                                            case $REPLY in
                                                    1) echo "猪肉大葱: 10";break 2;;
                                                    2) echo "素三鲜: 12";break 2;;
                                                    3) echo "韭菜鸡蛋:15";break 2;;
                                                    4) caidan;;
                                            esac
                                    done
                            ;;
                            4) exit;;
                    esac
            done
            }
            caidan


    信号捕捉trap
    trap ‘触发指令‘ 信号
    自定义进程收到系统发出的指定信号后,将执行触发指令,而不会执行原操作
    trap ‘‘ 信号
    忽略信号的操作
    trap ‘-‘ 信号
    恢复原信号的操作
    trap -p
    列出自定义信号操作

    trap示例

            #!/bin/bash
            trap ‘echo “signal:SIGINT"‘ int
            trap -p
            for((i=0;i<=10;i++));do
                    sleep 1
                    echo $i
            done
            trap ‘‘ int
            trap -p
            for((i=11;i<=20;i++));do
                    sleep 1
                    echo $i
            done
            trap ‘-‘ int
            trap -p
            for((i=21;i<=30;i++));do
                    sleep 1
                    echo $i
            done
    • 函数介绍

          函数function是由若干条shell命令组成的语句块,实现代码重用和模块化编程
          它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部分
          函数和shell程序比较相似,区别在于:
          1.Shell程序在子Shell中运行
          2. 而Shell函数在当前Shell中运行。因此在当前Shell中,函数可以对shell中变量进行修改
      
      定义函数
      ? 函数由两部分组成:函数名和函数体 ? help function
      ? 语法一:
      function f_name
      {
      ...函数体...
      }
      ? 语法二:
      function f_name ()
      {
      ...函数体...
      }
      ? 语法三:
      f_name ()
      {
      ...函数体...
      }
      
          函数使用
          ? 函数的定义和使用: – 可在交互式环境下定义函数 – 可将函数放在脚本文件中作为它的一部分 – 可放在只包含函数的单独文件中 ? 调用:函数只有被调用才会执行
          调用:给定函数名
          函数名出现的地方,会被自动替换为函数代码
          ? 函数的生命周期:被调用时创建,返回时终止
      
          检查载入函数
          使用set命令检查函数是否已载入。set命令将在shell中显示所有的载入函
          数

      示例:

          set
                  findit=( ){
                  if [ $# -lt 1 ]; the
                  echo "usage :findit file";
                  return 1
                  fi
                  find / -name $1 -print
          }…
      
          删除shell函数
          现在对函数做一些改动后,需要先删除函数,使其对shell不可用。使用unset命令完成删除函数
          命令格式为:
          unset function_name
          示例:
          unset findit
          再键入set命令,函数将不再显示
          环境函数
          使子进程也可使用
          声明:export –f function_name
          查看:export -f 或 declare -xf
      
          函数可以接受参数:
          传递参数给函数:调用函数时,在函数名后面以空白分隔给定参数列表即可;例如
          “testfunc arg1 arg2 ...”
          在函数体中当中,可使用$1, $2, ...调用这些参数;还可以使用[email protected], $*, $#等特殊变量
      
          马函数变量
          变量作用域:
          环境变量:当前shell和子shell有效
          本地变量:只在当前shell进程有效,为执行脚本会启动专用子shell进程;因此,本地变量
          的作用范围是当前shell脚本程序文件,包括脚本中的函数
          局部变量:函数的生命周期;函数结束时变量被自动销毁
          注意:如果函数中有局部变量,如果其名称同本地变量,使 用局部变量
          在函数中定义局部变量的方法
          local NAME=VALUE
    • 函数递归示例
          函数递归:
          函数直接或间接调用自身
          注意递归层数
          递归实例:
          阶乘是基斯顿·卡曼于 1808 年发明的运算符号,是数学术语
          一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且有0的阶乘为1,自然数n的
          阶乘写作n!
          n!=1×2×3×...×n阶乘亦可以递归方式定义:0!=1,n!=(n-1)!×n
          n!=n(n-1)(n-2)...1
          n(n-1)! = n(n-1)(n-2)!
      
          #!/bin/bash
          #fact() {
                  if [ $1 -eq 0 -o $1 -eq 1 ]; then
                  echo 1
                  else
                  echo $[$1*$(fact $[$1-1])]
                  fi
          }
          fact $1
      
          ×××
          fork×××是一种恶意程序,它的内部是一个不断在fork进程的无限循环,实质是一个简单的递归
          序。由于程序是递归的,如果没有任何限制,这会导致这个简单的程序迅速耗尽系统里面的所有资
          源
          函数实现
          :(){ :|:& };:
          bomb() { bomb | bomb & }; bomb
          脚本实现
          cat Bomb.sh
          #!/bin/bash
          ./$0|./$0&
    • 数组
          变量:存储单个元素的内存空间
          数组:存储多个元素的连续的内存空间,相当于多个变量的集合
          数组名和索引
          索引:编号从0开始,属于数值索引
          注意:索引可支持使用自定义的格式,而不仅是数值格式,即为关联
          索引,bash4.0版本之后开始支持
          bash的数组支持稀疏格式(索引不连续)
          声明数组:
          declare -a ARRAY_NAME
          declare -A ARRAY_NAME: 关联数组
          注意:两者不可相互转换

    数组赋值

            数组元素的赋值:
            (1) 一次只赋值一个元素;
            ARRAY_NAME[INDEX]=VALUE
            weekdays[0]="Sunday
            weekdays[4]="Thursday
            (2) 一次赋值全部元素:
            ARRAY_NAME=("VAL1" "VAL2" "VAL3" ...)
            (3) 只赋值特定元素:
            ARRAY_NAME=([0]="VAL1" [3]="VAL2" ...)
            (4) 交互式数组值对赋值
            read
            -a ARRAY
            显示所有数组:declare
            -a
    
            引用数组
            引用数组元素:
            ${ARRAY_NAME[INDEX]}
            注意:省略[INDEX]表示引用下标为
            0的元素
            引用数组所有元素:
            ${ARRAY_NAME[*]}
            ${ARRAY_NAME[@]}
            数组的长度
            (数组中元素的个数
            )
            :
            ${#ARRAY_NAME[*]}
            ${#ARRAY_NAME[@]}
            删除数组中的某元素:导致稀疏格式
            unset ARRAY[INDEX]
            删除整个数组
    
            unset ARRAY
            数组数据处理
            引用数组中的元素:
            数组切片:${ARRAY[@]:offset:number}
            offset: 要跳过的元素个数
            number: 要取出的元素个数
            取偏移量之后的所有元素
            ${ARRAY[@]:offset}
            向数组中追加元素:
            ARRAY[${#ARRAY[*]}]=value
            关联数组:
            declare -A ARRAY_NAME ARRAY_NAME=([idx_name1]=‘val1‘
            [idx_name2]=‘val2‘...)
            注意:关联数组必须先声明再调用

    示例
    生成10个随机数保存于数组中,并找出其最大值和最小值

            #!/bin/bash
            declare -a rand
            declare -i max=0
            declare –i min=32767
            for i in {0..9}; do
                    rand[$i]=$RANDOM
                    echo ${rand[$i]}
                    [ ${rand[$i]} -gt $max ] && max=${rand[$i]}
                    [ ${rand[$i]} -lt $min ] && min=${rand[$i]}
                    done
            echo "Max: $max Min:$min"

    示例
    编写脚本,定义一个数组,数组中的元素是/var/log目录下所有以.log结尾的
    文件;要统计其下标为偶数的文件中的行数之和

            #!/bin/bash
            #declare -a files
            files=(/var/log/*.log)
            declare -i lines=0
            for i in $(seq 0 $[${#files[*]}-1]); do
                    if [ $[$i%2] -eq 0 ];then
                    let lines+=$(wc -l ${files[$i]} | cut -d‘ ‘ -f1)
                    fi
            done
            echo "Lines: $lines."

    原文地址:http://blog.51cto.com/11912662/2134962

    时间: 2024-08-29 15:57:11

    shell高级编程的相关文章

    18道Shell高级编程企业实战题及参考答案(一)

    Shell高级编程企业实战题参考解答 ########################################################################### 让我们一起感谢,本文内容答案完全来自老男孩教育的学生-张耀课前上机考试解答! ########################################################################### 目录: 1.监控MySQL主从同步... 1 2.批量创建文件及改名... 3

    Linux Shell 高级编程技巧4----几个常用的shell脚本例子

    4.几个常用的shell脚本例子    4.0.在写脚本(同样适用在编程的时候),最好写好完善的注释    4.1.kill_processes.sh(一个杀死进程的脚本) #!/bin/bash current_PID=$$ ps -aux | grep "/usr/sbin/httpd" | grep -v "grep" | awk '{print $2}' > /tmp/${current_PID}.txt for pid in `cat /tmp/${

    shell高级编程企业实战题编程---是骡子是马 牵出来溜溜!

    企业合格的linux运维必会编程题,能独立完成的同学就业工资不会低于10K 这是老男孩linux运维班要求学生必会的题目,完不成的不能合格毕业,每个完成的都奖励价值500-1000元的等值礼物(以当天考试成绩宣布为准),要进要退自己抉择,伙伴们走起! 实战考试时间就在2015年4月15日上机实战,禁止大面积抄袭学习课堂笔记否则无奖励!共18道考试题,面授上课几乎全部讲解过类似的案例,考试题略微变更而已. 企业面试题1:(生产实战案例):监控MySQL主从同步是否异常,如果异常,则发送短信或者邮件

    Linux Shell 高级编程技巧2----shell工具

    2.shell工具    2.1.日志文件        简介            创建日志文件是很重要的,记录了重要的信息.一旦出现错误,这些信息对于我们排错是非常有用的:监控的信息也可以记录到日志文件        常用的日志文件的方法            以时间为标识的日志文件                例子 #!/bin/bash #当前的日期 current_date=`date "+%Y%m%d"` #今天的日志文件名 todaylog="log/${cu

    Linux Shell 高级编程技巧3----运行级别脚本介绍

    3.运行级别脚本介绍    3.1.运行级别        运行级别介绍:            0    关机            1    单用户模式            2    多用户模式,没有NFS服务            3    多用户模式            4    目前还没有使用            5    X windows 的启动模式            6    重启计算机        运行级别对应的目录(/etc/rcN.d,N是数字0.1.2...)

    Shell高级编程7:Shell的字符串表达式介绍

    字符串测试操作符 字符串测试操作符的作用:比较两个字符串是否相同.字符串长度是否为0,字符串是否为 NULL(注:bash区分零长度字符串和空字符串)等 在书写测试表达式时,可以使用下表中的字符串测试操作符. 下表:字符串测试操作符 常用字符串测试操作符 两端 -z 若串长度为0则真,-z可以理解为zero -n 若串长度不为0则真,-z可以理解为no zero "串1" = "串2" 若串1等于串2则真,可使用"=="代替"=&quo

    Linux Shell 高级编程技巧1---深入讨论(awk、&lt;&lt;)

    1.深入讨论(awk.<<)    1.1.深入讨论awk        记录和域,模式和动作,正则表达式和元字符            基础教程中已经介绍        条件和逻辑操作符            <    小于            >=    大于等于            <=    小于等于            ==    等于            !=    不等于            ~    匹配正则表达式            !~    

    shell高级编程三剑客之sed实践讲解

    功能说明: sed stream editor(流编辑)增删改查  过滤,取行 sed --version查看sed版本 man sed 语法格式: sed    [options]    [sed-commands]     [input-file]           (sed语句) sed  选项                sed命令               输入文件 sed命令可以是多个或则是一个, [input-file] 输入文件可以是真实存在的文件也可以通过管道  可以是文

    运维人员如何学好shell脚本编程

    核心:练-->想-->再练-->再想! 运维人员如何学好shell脚本编程老男孩linux早期毕业的学生谈如何学好shell编程技巧该生毕业后一年任职一家近千人公司的运维经理.目前就职小米科技1.基本语法,敲n+1遍.为什么不是n遍那,因为n遍是你刚开始为了编程而努力的几天,  1是说你以后要每天都要写写想想,至少是要看看.2.各种基本语法,if多种判断都要会,这样做不是为了什么都要学而是为了看懂别人的  代码. 这个要写一段时间,各种都用.3.解决上边说的问题,各种语法都要学的问题,现