zoukankan      html  css  js  c++  java
  • shell脚本编程进阶

    在linux shell中,通常我们将一些命令写在一个文件中就算是一个shell脚本了,但是如果需要执行更为复杂的逻辑判断,我们就需要使用流程控制语句来支持了。
    所谓流程控制既是通过使用流程控制语句对程序流程的选择、循环、转向和返回等进行控制。流程控制是所有编程语言分重要组成部分,linux shell同样有一套自己的流程控制语句,其中主要包括条件语句(if),循环语(for,while),选择语句(case)。

    条件选择if语句

    单分支

    if判断条件;then
    
          条件为真的分支代码
    
    fi

    双分支

    if 判断条件; then 
       条件为真的分支代码 
    else 
       条件为假的分支代码 
    fi

    多分支

    if 判断条件1; then 
       条件为真的分支代码 
    elif 判断条件2; then 
       条件为真的分支代码 
    elif 判断条件3; then 
       条件为真的分支代码 
    else 
       以上条件都为假的分支代码 
    fi

    逐个条件进行判断,第一次为“真”条件时,接着执行其分支,而后结束整个if语句

    条件判断case语句

    case 变量引用 in        #变量的引用加$
    PAT1) 
        分支1 
        ;;
    PAT2) 
        分支2 
        ;;
    ... 
    *) 
        默认分支 
        ;; 
    esac

    case支持glob风格的通配符:
    *: 任意长度任意字符
    ?: 任意单个字符
    []:指定范围内的任意单个字符
    a|b: a或b

    练习
    1、编写脚本/root/bin/createuser.sh,实现如下功能:使用一个用户名做为参数,如果
    指定参数的用户存在,就显示其存在,否则添加之;显示添加的用户的id号等信息

    #!/bin/bash

    read -p "please input username:" username
    useradd $username &> /dev/null
    if [ $? -eq 0 ];then
        echo "add $username user" && id $username
    else
        echo "the user already exits"
    fi

    2、编写脚本/root/bin/yesorno.sh,提示用户输入yes或no,并判断用户输入的
       是yes还是no,或是其它信息

    #!/bin/bash

    read -p "Do you agree? yes or no: " ANS
    if [ -z "$ANS" ] ;then
       echo "Please input yes or no"
       exit
    fi
    case $ANS in
    [Yy]|[Yy][Ee][Ss])
       echo "Your answer is YES"
       ;;
    [Nn]|[Nn][Oo])
       echo "Your answer is NO"
       ;;
    *)
       echo "Your answer is fales"
    esac

    3、编写脚本/root/bin/filetype.sh,判断用户输入文件路径,显示其文件类型
     (普通,目录,链接,其它文件类型)

    #!/bin/bash

    read -p "input file or dir:" choose
    [ -z "$choose" ] && echo "Please input a file or dir"
    if [ -d "$choose" ] ;then
       echo "$choose is directory"
    elif [ -L "$choose" ] ;then
       echo "$choose is a link"
    elif [ -f "$choose" ] ;then
       echo "$choose is a common file"
    else
       echo "$choose is other type"
    fi

    4、编写脚本/root/bin/checkint.sh,判断用户输入的参数是否为正整数

    #!/bin/bash

    read -p "input a digit:" NUM
    if [[ "$NUM" =~ ^[0-9]+$ ]] ;then
       echo "$NUM is a int"
    fi

    循环

    循环执行

      将某代码段重复运行多次

      重复运行多少次

        循环次数事先已知

        循环次数事先未知

      有进入条件和退出条件

    for, while, until

    for循环

    for 变量名 in 列表;
    
    do
    
       循环体
    
    done
    
    执行机制:
    
        依次将列表中的元素赋值给“变量名”; 每次赋值后即执行一次循环体; 直 到列表中的元素耗尽,循环结束
    列表生成方式:
    (1) 直接给出列表
       for num in 1 2 3 4 5;do echo The number is $num ;done
       The number is 1
       The number is 2
       The number is 3
       The number is 4
       The number is 5
    
    (2) 整数列表:
       (a) {start..end}
        for num in {10..1..3};do echo The numberis $num ;done
         The numberis 10
         The numberis 7
         The numberis 4
         The numberis 1
       (b) $(seq [start [step]] end)
        for num in `seq 2 4 10`;do echo The number is $num ;done
         The number is 2
         The number is 6
         The number is 10
    
    (3) 返回列表的命令 $(COMMAND)
    (4) 使用glob,如:*.sh
       for num in "/root/bin/*.sh";do echo The filename is $num ;done
        The filename is /root/bin/*.sh
    (5) 变量引用; $@独立, $*整体(位置变量)

    多行重定向

    练习:
    用for实现
    1、打印国际象棋
    for i in {1..8};do
        for j in {1..4};do
            if [ $[i%2] -eq 0 ];then 
                echo -e "33[1;41m 33[0me[1;43m e[0mc"
           else
                echo -e "e[1;43m e[0me[1;41m e[0mc"
           fi
        done
        echo
    done
    
     c=-n默认不转行
    
    e  e[0m=033  033[0m颜色提示符
    
    2、添加10个用户user1-user10,密码为magedu
    for i in {1..10};do 
    if id $i &> /dev/null ;then
    
        echo "user$i is exist"
    else
        useradd user$i &>/dev/null
        echo "magedu" | passwd --stdin user$i &>/dev/null
        echo "user $i add successful"
    fi
    done
    
    注:批量删除用户for i in {1..10};do userdel -r(删除家目录) user$i;done
    
    3、/etc/rc.d/rc3.d目录下分别有多个以K开头和以S开头的文件;分别读取每个文件,
    以K开头的输出为文件加stop,以S开头的输出为文件名加start,如K34filename stop
    S66filename start
    #!/bin/bash
    for i in $(ls /etc/rc.d/rc3.d/);do
            if [[ $i =~ ^K.* ]];then
                    echo "$i stop"
            elif [[ $i =~ ^S.* ]];then
                    echo "$i start"
            fi
    done
    4、编写脚本,提示输入正整数n的值,计算1+2+…+100的总和
    #!/bin/bash
    
    declare -i sum=0 n=100
        for i in {1..100};do
        let sum=sum+i | sum+=i
    done
    echo sum=$sum
    unset sum
    5、计算100以内所有能被3整除的整数之和
    #!/bin/bash
    sum=0
    for i in {1..100};do
        if [ $[$i%3] -eq 0 ];then
        let sum+=$i
        fi  
    done
    echo $sum
    6、编写脚本,提示请输入网络地址,如192.168.0.0,判断输入的网段中主机在线状态
    net=192.168.140 
       for i in {1..254};do
         { if ping -c1 -w1 $net .$i &> /dev/null ;then
         echo $net.$i is up
       else
        echo $net.$i is down
        fi; } & 并行在后台执行
    done
    wait
    
    7、打印九九乘法表
    #!/bin/bash
    
    for i in {1..9};do 
       for j in `seq 1 $i`;do
           result=$[$j*$i]
           echo -e "$j*$i=$result c"
       done
       echo
    done
    
    8、在/testdir目录下创建10个html文件,文件名格式为数字N(从1到10)加随机8个字
    母,如:1AbCdeFgH.html
    取随机字母openssl rand -base64 20 | tr -dc '[:alpha:]' | head -c8
    9、打印等腰三角形
    *的个数=line*2-1
    空格=总line-当前line
    #!/bin/bash
    read -p "Please input lines:" L
    for i in `seq ${L}`;do
        for (( j=${L};j>i;j-- ));do
            echo -n " "
        done
        for j in `seq 1 $i`;do
            echo -n "*"
        done
        for (( n=1;n<i;n++ ));do
        echo -n "*"
        done
        echo " "
    done

     打印等腰三角形并且颜色随机

    #!/bin/bash
    read -p "Please input lines:" L for i in `seq ${L}`;do for j in `seq $[$L-i]`;do echo -n " " done for k in `seq $[i*2-1]`;do let color=$RANDOM%7+31 echo -ne "e[1;5;${color}m*e[0m" done echo done

    while循环

    while 条件;do
         循环体
      done
    条件(CONDITION):循环控制条件;进入循环之前,先做一次判断;每次循环之后会再次做判断;条件为"ture",
    则执行一次循环;直到条件测试状态为“false”终止循环。
    
    因此:CONDTION一般应该有循环控制变量;而此变量的值会在循环体不断地 被修正
    
    进入条件:CONDITION为true
    
    退出条件:CONDITION为false
    练习:
    1
    、编写脚本,求100以内所有正奇数之和 #!/bin/bash
    declare
    -i sum=0 i=1 while [ $i -le 100 ];do let sum=sum+i let i=i+2 done echo sum=$sum 2、编写脚本,提示请输入网络地址,如192.168.0.0,判断输入的网段中主机 在线状态,并统计在线和离线主机各多少

    #!/bin/bash

    net=192.168.140
    let num=1
    x=0(up的主机)
    y=0(down的主机数)
    while [ ${num} -le 254 ];do
    ping -c1 -w1 "${net}.${num}" &>/dev/null
      if [ $? -eq 0 ];then
        echo "${net}.${num} is up"
        x=$(($x+1))
      else
        echo "${net}.${num} is down"
        y=$(($y+1))
      fi
    num=$(($num+1))
    done
    echo "total ${x} hosts are up"
    echo "total ${y} hosts are down "

    3、编写脚本,打印九九乘法表

    #!/bin/bash

    declare -i i=1
    while [ $i -le 9 ];do
        declare -i j=1
        while [ $j -le $i ];do
           result=$[$i*$j]
           echo -e "${j}x${i}=$result c"  是产生空格并对齐;c是不换

           let j++

        done
        echo
        let i++
    done

    4、编写脚本,利用变量RANDOM生成10个随机数字,输出这个数字,并显
    示其中的最大值和最小值

    #!/bin/bash

    declare -i a=0
    max=0
    min=$RANDOM
    while [ $a -le 9 ];do
    num=$RANDOM
      if [ $num -le $max ];then
        if [ $num -le $min ];then
          min=$num
          fi
      else
          max=$num
      fi
      let a++:q!:
    done
    echo "the min number is $min,the max number is $max"

    5、编写脚本,实现打印国际象棋棋盘

    #!/bin/bash

    let i=0
    while [ $i -le 15 ];do
      for ((j=0;j<4;j++));do
        if [ $[i%4] -eq 0 -o $[i%4] -eq 1 ];then
          echo -e "33[1;41m 33[0m33[1;47m 33[0mc"
        else
          echo -e "33[1;47m 33[0m33[1;41m 33[0mc"

        fi
      done
      echo
      let i++
    done

    6、后续六个字符串:efbaf275cd、4be9c40b8b、44b2395c46、
    f8c8873ce0、b902c16c8b、ad865d2f63是通过对随机数变量RANDOM随机
    执行命令: echo $RANDOM|md5sum|cut –c1-10 后的结果,请破解这些
    字符串对应的RANDOM值while循环

     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

    循环控制语句brek

    用于循环体中
    break [N]:提前结束第N层循环,最内层为第1层
     while CONDTIITON1; do
    CMD1
    ...
    if CONDITION2; then
    break
    fi
    CMDn
    ...
     done

    创建无限循环

    while true; do

      循环体

    done

    until false; do

       循环体

    Done

    练习
    1、每隔3秒钟到系统上获取已经登录的用户的信息;如果发现用户hacker登录,
    则将登录时间和主机记录于日志/var/log/login.log中,并退出脚本
    #!/bin/bash

    until `who | grep -o "^usr" &>/dev/null`;do
        sleep 3
    done
    echo "user is logining"
    who | grep "user" >> /data/login.sh:q!

    2、随机生成10以内的数字,实现猜字游戏,提示比较大或小,相等则退出

    #!/bin/bash

    i=$[$RANDOM%11]
    while read -p "please input a number:" a;do
      [[ $a =~ ^[0-9]+$ ]] || { echo "please input a dight:1-10";continue; }
      if [ $i -gt $a ];then
        echo little
      elif [ $i -lt $a ];then
        echo more
      else
        echo right
        break
      fi
    done

    3、用文件名做为参数,统计所有参数文件的总行数

    if [ $# -eq 0 ];then  $#是所有未知变量
      echo "please input file path"
     else
      until [ -z "$1" ];do -z判断文件是否为空
        echo "tongji file:$1"
        echo "the file total line are: `wc -l $1 | cut -d " " -f1`“
        echo
        shift
    done
    echo "finish"
    fi

    4、用二个以上的数字为参数,显示其中的最大值和最小值

    函数:function

    是由若干条shell命令组成的语句块,实现代码重用和模块化编程;函数只有被调用才会执行

    语法1:
    
    function func_name {
    
      函数体
    
    }
    
    语法2::
    
    func_name() {
    
      函数体
    
    }

    注意:函数中变量的生效范围是当前所在shell

    函数的生命周期:被调用时创建,返回时终止

    函数在使用前必须定义,因此应将函数定义放在脚本开始部分,直至shell首次发现它后才能使用,调用函数时就像使用命令一样调用

    return #:在函数中使用,跳出函数,返回值 #;如果没有定义退出返回值则函数的默认返回值为函数中最后一条命令的返回值

    local var:声明函数为本地变量,只在函数内部生效

    declare

      -f func_name 查看指定函数

      -xf func_name 声明函数的生效范围为全局 == export -f func_name

      -i 声明变量为数字

      -g 在函数中使用,声明变量为普通变量

      declare 在函数中用隐式使用了local,定义的变量为本地变量

    函数的递归调用:在函数中调用函数本身

    fork炸弹

    bome() { bome|bome& }; bome

    编写脚本copycmd.sh

    • (1) 提示用户输入一个可执行命令名称;
    • (2) 获取此命令所依赖到的所有库文件列表;
    • (3) 复制命令至某目标目录(例如/mnt/sysroot)下的对应路径下;
      • 如:/bin/bash ==> /mnt/sysroot/bin/bash
    • (4) 复制此命令依赖到的所有库文件至目标目录下的对应路径下;(5)每次复制完成一个命令后,不要退出,而是提示用户键入新的要复制的命令,并重复完成上述功能;直到用户输入quit退出;
      • 如:/lib64/ld-linux-x86-64.so.2 ==> /mnt/sysroot/lib64/ld-linux-x86-64.so.2
    复制代码
    #!/bin/bash
    . my_functions
    Ddir="/mnt/sysroot"
    [ ! -d "$Ddir" ] && mkdir "$Ddir"
    
    cpbin() {
            cmddir=`echo "$Cmd_path" |grep -o ".*/"`
            [ ! -d "${Ddir}${cmddir}" ] && mkdir -p "${Ddir}${cmddir}"
            cp -n "$Cmd_path" "${Ddir}${cmddir}"
    }
    
    libcp() {
            echo "$Lib_path" |while read line ;do
                    libdir=`echo "$line" |grep -o ".*/"`
                    [ ! -d "${Ddir}${libdir}" ] && mkdir -p "${Ddir}${libdir}"
                    cp -n "$line" "${Ddir}${libdir}" 2>/dev/null
            done
    }
    
    while read -p "Input a cmd. (quit): " CMD ;do
            if [ "$CMD" == 'quit' ] ;then echo "Think you! Bye bye."; break; fi
            if ! which "$CMD" &>/dev/null ;then 
                    echo "not find $CMD, please input again."
                    failed "copy $CMD failed."
                    continue
            fi
            Cmd_path=`which $CMD |grep -o "/.*"`
            Lib_path=`ldd $Cmd_path |sed -nr 's#.*[[:space:]]+(/.*) .*#1#p'`
            cpbin
            libcp
            success "copy $CMD Complete."
    done
    复制代码

     求斐波那契数列的第N个数

    复制代码
    #!/bin/bash
    feibo() {
        if [ $1 -eq 0 ] ; then
            echo 0
        elif [ $1 -eq 1 ] ;then
            echo 1
        else
            echo $[`feibo $[$1-1]`+`feibo $[$1-2]`]
        fi
    }
    
    read -p "please a num: " n
    复制代码

     求N的阶乘

    复制代码
    #!/bin/bash
    fact() {
            if [ $1 -eq 0 -o $1 -eq 1 ] ;then
                    echo 1
            else
                    echo $[$1*`fact $[$1-1]`]
            fi
    }
    
    fact $1
  • 相关阅读:
    django添加检查用户名和手机号数量接口
    1.vue发送短信逻辑
    Celery 配置与基本使用 并且用celery 一步发送短信
    递归基础_并查集思想_二叉树最大深度问题
    递归基础_汉诺塔问题_经典的多状态问题_整体法/分两个函数互相递归
    递归基础_全排列+改写_组合数
    递归基础_组合数_输出的各种办法(递归)_(持续更新)
    关于gpu版本的tensorflow+anaconda的一些安装问题(持续更新)
    吴恩达课程笔记_1-1~1-4
    bfs和dfs辨析—基础复习(从stack和queue的角度来理解区别,加深理解,不再模糊)
  • 原文地址:https://www.cnblogs.com/yaun1498078591/p/9005279.html
Copyright © 2011-2022 走看看