zoukankan      html  css  js  c++  java
  • Linux Shell脚本编程提高

    该系列文章只是本人的学习笔记,文章中的文字描述提取自《Linux鸟哥私房菜》《Linux运维之道》等书中的重点内容,化繁为简能够在工作中快速复习掌握重点,并不代表个人立场,但转载请加出处,并注明参考文献。

    实际上Shell是一个命令解释器,它解释由用户输入的命令并且把它们送到内核,不仅如此,Shell有自己的编程语言用于对命令的编辑,它允许用户编写由shell命令组成的程序.Shel编程语言具有普通编程语言的很多特点,比如它也有循环结构和分支控制结构等,用这种编程语言编写的Shell程序与其他应用程序具有同样的效果,下面我们会介绍Shell-Script的编写.

    Shell 条件判断

    ◆按文件类型判断◆

    1.使用 [] 来执行判断,并使用echo $? 判断执行结果

    [root@localhost ~]# ls
    lyshark.log  passwd.awk
    
    [root@localhost ~]# [ -e ./lyshark.log ]
    [root@localhost ~]# echo $?              #返回0表示文件 ./lyshark.log 存在
    0
    
    [root@localhost ~]# [ -e ./shar ]        #返回1表示文件 ./shar 不存在
    [root@localhost ~]# echo $?
    1
    

    2.我们可以结合之前所学的 && 和 || 实现判断后输出判断结果

    [root@localhost ~]# ls
    lyshark.log  passwd.awk
    
    [root@localhost ~]# [ -e ./lyshark.log ] && echo "check ok" || echo "None"
    check ok
    
    [root@localhost ~]# [ -e ./shar ] && echo "check on" || echo "None"
    None
    

    ◆按文件权限判断◆

    1.使用 -r 判断文件是否可读,和可执行

    [root@localhost ~]# ls
    lyshark.log passwd.awk
    
    [root@localhost ~]# [ -r ./lyshark.log ] && echo "check ok" || echo "None"
    check ok
    
    [root@localhost ~]# [ -x ./lyshark.log ] && echo "check ok" || echo "None"
    None
    
    [root@localhost ~]# [ -r ./lyshark.log ] && [ -x ./lyshark.log ] && echo "可读,可执行" || echo "可读,不可执行" || echo
    "不可读,不可执行"
    
    可读,不可执行
    

    ◆两文件之间的比较◆

    1.通过 -ef 判断是否是相同的I节点

    [root@localhost ~]# ls -li
    total 0
    8409155 -rw-r--r-- 2 root root 0 Sep 25 21:39 lyshark_ln.log
    8409155 -rw-r--r-- 2 root root 0 Sep 25 21:39 lyshark.log
    
    [root@localhost ~]# [ ./lyshark.log -ef lyshark_ln.log ] && echo "ok" || echo "no"
    ok
    

    ◆数值之间的比较◆

    1.比较两数字,大小关系

    [root@localhost ~]# [ 23 -ge 24 ] && echo "23 >= 24 " || echo "23 <= 24"
    23 <= 24
    
    [root@localhost ~]# [ 30 -ge 24 ] && echo "30 >= 24 " || echo "30 <= 24"
    30 >= 24
    

    ◆字符串之间的比较◆

    1.字符串之间的比较例子,字符串是否为空

    [root@localhost ~]# name=LyShark
    [root@localhost ~]# age=""
    [root@localhost ~]# unset sex
    
    [root@localhost ~]# [ -z "$name" ] && echo "字符串空" || echo "不为空"
    不为空
    
    [root@localhost ~]# [ -z "$age" ] && echo "字符串空" || echo "不为空"
    字符串空
    
    [root@localhost ~]# [ -z "$sex" ] && echo "字符串空" || echo "不为空"
    字符串空
    

    2.两个字符串相等比较

    [root@localhost ~]# x=100
    [root@localhost ~]# y=200
    [root@localhost ~]# z=100
    
    [root@localhost ~]# [ "x" == "y" ] && echo "yes" || echo "no"
    no
    [root@localhost ~]# [ "$x" == "$y" ] && echo "yes" || echo "no"
    no
    
    [root@localhost ~]# [ "$x" == "$z" ] && echo "yes" || echo "no"
    yes
    

    ◆多重条件判断◆

    1.逻辑与:判断变量x不为空,并且x大于20

    [root@localhost ~]# declare -i x=10
    [root@localhost ~]# [ -n "$x" -a "$x" -gt 20 ] && echo "yes" || echo "no"
    no
    [root@localhost ~]# declare -i x=30
    [root@localhost ~]# [ -n "$x" -a "$x" -gt 20 ] && echo "yes" || echo "no"
    yes
    

    2.逻辑非:判断x变量不为空,或!取反

    [root@localhost ~]# declare -i x=30
    
    [root@localhost ~]# [ -n "$x" ] && echo "yes" || echo "no"
    yes
    
    [root@localhost ~]# [ ! -n "$x" ] && echo "yes" || echo "no"
    no
    

    IF条件判断

    if、then、else语句用于判断给定的条件是否满足,并根据测试条件的真假来选择相应的操作.if/else仅仅用于两分支判断,多分支的选择时需要用到if/else语句嵌套、if/elif/else和case多分支选择判断结构.

    IF结构例子: 一个就简单的单分支结构.测试条件后如果没有";"则then语句要换行.

    #!/bin/sh
    echo "Please input a Number:"
    read Num
     
    if [ "$Num" -lt 15 ]
    then
    	echo "$Num <= 15"
    fi
    

    IF/IF-ELSE结构: 一个双分支结构,如下执行删除文件,成功返回then是否返回else.

    #!/bin/sh
     
    echo "Please input the file which you want to delete:"
    read file
     
    if rm -f "$file"
    then
      echo "Delete the file $file  sucessfully!"
    else
      echo "Delete the file $file failed!"
    fi
    

    IF/ELSE嵌套: 可同时判断三个或三个以上条件,但要注意if与else配对关系,else语句总是与它上面最近的未配对的if配对.

    #!/bin/bash
    #提示用户输入分数(0-100)
    echo "Please Input a integer(0-100): "
    read score
    
    #判断学生的分数类别
    if [ "$score" -lt 0 -o "$score" -gt 100 ]
    then
       echo "The score what you input is not integer or the score is not in (0-100)."
    else
         if [ "$score" -ge 90 ]
         then
             echo "The grade is A!"
         else
              if [ "$score" -ge 80 ]
              then
                  echo "The grade is B!"
              else
                   if [ "$score" -ge 70 ]
                  then
                       echo "The grade is C!"
                  else
                       if [ "$score" -ge 60 ]
                       then
                            echo "The grade is D!"
                       else
                            echo "The grade is E!"
                       fi
                  fi
             fi
        fi
    fi
    

    IF/ELIF/ELSE结构: if/else嵌套在编程中很容易漏掉then或fi产生错误,而且可读性很差,因此引入if/elif/else结构针对某一事件的多种情况进行处理,fi只出现一次,可读性也提高了.

    #!/bin/bash  
     
    echo "Please Input a integer(0-100): "
    read score
     
    if [ "$score" -lt 0 -o "$score" -gt 100 ]
    then
        echo "The score what you input is not integer or the score is not in (0-100)."
    elif [ "$score" -ge 90 ]
    then
        echo "The grade is A!"
    elif [ "$score" -ge 80 ]
    then
        echo "The grade is B!"
    elif [ "$score" -ge 70 ]
    then
        echo "The grade is C!"
    elif [ "$score" -ge 60 ]
    then
        echo "The grade is D!"
    else
        echo "The grade is E!"
    fi
    

    实例1: 通过单分支判断磁盘是否已满.

    [root@localhost ~]# cat if.sh
    
    #!/bin/bash
    
    ret=$( df -h | grep "/dev/sda1" | awk '{printf $5}' | cut -d "%" -f 1 )
    if [ $ret -ge 80 ]
    then
            echo -e "/dev/sda1 is full !!"
    fi
    

    实例2: 通过多分支判断磁盘是否已满.

    [root@localhost ~]# cat if.sh
    #!/bin/bash
    
    ret=$( df -h | grep "/dev/sda1" | awk '{printf $5}' | cut -d "%" -f 1 )
    if [ $ret -ge 80 ]
    then
            echo -e "/dev/sda1 is full !"
    else
            echo -e "/dev/sda1 is not full !"
    fi
    

    实例3: 多分支判断小例子.

    [root@localhost ~]# cat if.sh
    #!/bin/bash
    
    read -p "输入一个数字:" num
    
    if [ "$num" -gt "100" ]
    then
            echo -e "这个数大于100"
    elif [ "$num" -lt "100" ]
    then
            echo -e "这个数小于100"
    elif [ "$num" -eq "100" ]
    then
            echo -e "这个数等于100"
    fi
    

    实例4: 判断输入的年份是否是润年(润年条件:1、能被4整除,但不能被100整除的年份.2、能被100整除,又能被400整除的年份)

    #!/bin/sh
      
    echo "Please Input a year: "
    read year
     
    let "n1=$year % 4"
    let "n2=$year % 100"
    let "n3=$year % 400"
    if [ "$n1" -ne 0 ]
    then
        leap=0
    elif [ "$n2" -ne 0 ]
    then
        leap=1
    elif [ "$n3" -ne 0 ]
    then
        leap=0
    else
        leap=1
    fi
    

    CASE分支结构

    case结构变量值依次比较,遇到双分号则跳到esac后的语句执行,没有匹配则脚本将执行默认值*"后的命令,直到"';;"为止.case的匹配值必须是常量或正则表达式.

    #!/bin/bash
    
    read -p "输入一个符号:" temp
    
    case $temp in
    
            "-print")
                    echo -e "您执行了print函数"
            ;;
            "-save")
                    echo -e "您执行了save函数"
            ;;
            "-help")
                    echo -e "您执行了help函数"
            ;;
            *)
                    echo -e "您执行了其他操作"
            ;;
    esac
    

    FOR循环结构

    Shell编程中循环命令用于特定条件下决定某些语句重复执行的控制方式,有三种常用的循环语句:for、while和until.while循环和for循环属于"当型循环",而until属于"直到型循环",循环控制符:break和continue控制流程转向.

    列表FOR循环: 循环打印数据分别从1遍历到5.

    do和done之间的命令称为循环体,执行次数和list列表中常数或字符串的个数相同.for循环,首先将in后list列表的第一个常数或字符串赋值给循环变量,然后执行循环体,以此执行list,最后执行done命令后的命令序列.

    #!/bin/bash
     
    for tmp in {1..5}
    do
         echo "Hello, Welcome $tmp times"
    done
    

    FOR循环累加: 通过FOR循环累加打印数据.

    通过i的按步数2不断递增,计算sum值为2500.同样可以使用seq命令实现按2递增来计算1~100内的所有奇数之和,for i in $(seq 1 2 100),seq表示起始数为1,跳跃的步数为2,结束条件值为100.

    #!/bin/bash
    sum=0
     
    for i in {1..100..2}
    do
        let "sum+=i"
    done
    
    echo "sum=$sum"
    

    FOR循环遍历目录: 通过for循环显示当前目录下所有的文件.

    #!/bin/bash
     
    for file in $( ls )
    #for file in *
    do
       echo "file: $file"
    done
    

    不带列表FOR: 由用户制定参数和参数的个数,与上述的for循环列表参数功能相同.

    #!/bin/bash
    
    echo "number of arguments is $#"
    echo "What you input is: "
    
    for argument
    do
        echo "$argument"
    done
    

    C风格FOR循环: 也被称为计次循环.

    #!/bin/bash
    for((integer = 1; integer <= 5; integer++))
    do
        echo "$integer"
    done
    

    实例1: 通过for循环打印1-10.

    [root@localhost ~]# cat for.sh
    #!/bin/bash
    
    for temp in `seq 1 10`
    do
            echo -e "打印数据: $temp"
    done
    

    实例2: 通过for循环计算1-100的累加和.

    [root@localhost ~]# cat for.sh
    #!/bin/bash
    
    declare -i sum=0
    
    for temp in `seq 1 100`
    do
            sum=$sum+$temp
    done
    
    echo -e "从1+到100的结果是: $sum"
    

    实例3: 从列表中选择数据.

    [root@localhost ~]# cat for.sh
    #!/bin/bash
    
    for temp in 1 3 5 7 9
    do
            echo -e "打印: $temp"
    done
    
    [root@localhost ~]# bash for.sh
    打印: 1
    打印: 3
    打印: 5
    打印: 7
    打印: 9
    

    实例4: 读取文件内容并打印.

    [root@localhost ~]# cat for.sh
    #!/bin/bash
    
    world=`cat /etc/passwd`
    for temp in $world
    do
            echo -e "打印: $temp"
    done
    

    WHILE 循环

    也称为前测试循环语句,重复次数是利用一个条件来控制是否继续重复执行这个语句.为了避免死循环,必须保证循环体中包含循环出口条件即表达式存在退出状态为非0的情况.

    计数控制: 指定了循环的次数500,初始化计数器值为1,不断测试循环条件i是否小于等于100.在循环条件中设置了计数器加2来计算1~100内所有的奇数之和.

    #!/bin/bash
     
    sum=0
     
    i=1
     
    while(( i <= 100 ))
    do
         let "sum+=i"
         let "i += 2"   
    done
     
    echo "sum=$sum"
    

    结束标记控制的while循环: 设置一个特殊的数据值(结束标记)来结束while循环.

    #!/bin/bash
     
    echo "Please input the num(1-10) "
    read num
     
    while [[ "$num" != 4 ]]
    do 
       if [ "$num" -lt 4 ]
       then
            echo "Too small. Try again!"
            read num
       elif [ "$num" -gt 4 ]
       then
             echo "To high. Try again" 
             read num
       else
           exit 0
        fi
    done 
     
    echo "Congratulation, you are right! "
    

    标志控制的while循环: 使用用户输入的标志值来控制循环的结束(避免不知道循环结束标志的条件).

    #!/bin/bash
     
    echo "Please input the num "
    read num
     
    sum=0
    i=1
     
    signal=0
     
    while [[ "$signal" -ne 1 ]]
    do
        if [ "$i" -eq "$num" ]
        then 
           let "signal=1"
           let "sum+=i"
           echo "1+2+...+$num=$sum"
        else
           let "sum=sum+i"
           let "i++"
        fi
    done
    

    命令行控制的while循环: 使用命令行来指定输出参数和参数个数,通常与shift结合使用,shift命令使位置变量下移一位($2代替$1、$3代替$2,并使$#变量递减),当最后一个参数显示给用户,$#会等于0,$*也等于空.

    #!/bin/bash
    
    echo "number of arguments is $#"
    echo "What you input is: "
     
    while [[ "$*" != "" ]]
    do
        echo "$1"
        shift
    done
    

    while计算: 通过while循环,计算1-100的累加和.

    [root@localhost ~]# cat while.sh
    #!/bin/bash
    
    declare -i x=0
    declare -i num=0
    
    while [ "$x" -lt "100" ]
    do
            x=$x+1
            num=$num+$x
    done
    
    echo -e "从1-100结果是: $num"
    
    [root@localhost ~]# bash while.sh
    从1-100结果是: 5050
    

    UNTIL 循环

    until命令和while命令类似,while能实现的脚本until同样也可以实现,但区别是until循环的退出状态是不为0,退出状态是为0(与while刚好相反),即whie循环在条件为真时继续执行循环而until则在条件为假时执行循环.

    #!/bin/bash
     
    i=0
     
    until [[ "$i" -gt 5 ]]    #大于5
    do
        let "square=i*i"
        echo "$i * $i = $square"
        let "i++"
    done
    
    #!/bin/bash
     
    for (( i = 1; i <=9; i++ ))
    do
        
        for (( j=1; j <= i; j++ ))
        do
            let "temp = i * j"     
            echo -n "$i*$j=$temp  "
         done 
         
         echo ""   #output newline
    done
    
    #!/bin/bash
    
    i=0
    
    until [[ "$i" -gt 5 ]]    #大于5
    
    do
    
        let "square=i*i"
    
        echo "$i * $i = $square"
    
        let "i++"
    
    done
    

    跳出语句(break,continue)

    break: 在for、while和until循环中break可强行退出循环,break语句仅能退出当前的循环,如果是两层循环嵌套,则需要在外层循环中使用break.

    #!/bin/bash
     
    sum=0
    for (( i=1; i <= 100; i++))
    do 
        let "sum+=i"
     
        if [ "$sum" -gt 1000 ]
        then
            echo "1+2+...+$i=$sum"
            break
        fi
    done
    

    continue: 在for、while和until中用于让脚本跳过其后面的语句,执行下一次循环.continue用于显示100内能被7整除的数.

    #!/bin/bash
     
    m=1
    for (( i=1; i < 100; i++ ))
    do
        let "temp1=i%7"         #被7整除
     
        if [ "$temp1" -ne 0 ]
        then
            continue
        fi
        
        echo -n "$i  "
        
        let "temp2=m%7"          #7个数字换一行
        
        if  [ "$temp2" -eq 0 ]
        then
            echo ""
        fi
        
        let "m++"
    done
    

    SELECT 语句

    select结构从技术角度看不能算是循环结构,只是相似而已,它是bash的扩展结构用于交互式菜单显示,功能类似于case结构比case的交互性要好.

    [root@localhost ~]# cat select.sh
    #!/bin/bash
    
    echo -e "请选择系统类型?"
    
    select var in "Linux" "GNU HURD" "FreeBSD" "Other";
    do
            if [ $var == "Linux" ]
            then
                    echo -e "您的系统是Linux"
            elif [ $var == "FreeBSD" ]
            then
                    echo -e "您的系统是FreeBSD"
            fi
    break
    done
    [root@localhost ~]# bash select.sh
    请选择系统类型?
    1) Linux
    2) GNU HURD
    3) FreeBSD
    4) Other
    
    #? 1
    您的系统是Linux
    
    
    #!/bin/bash
    
    declare -a serial
    serial=(1 2 3 4)
    PS3="Enter a number: "
    
    
    select var in "a" "b" "c" "d"
    do
        if ! echo ${serial[@]} | grep -q $REPLY
            then
                    echo "please enter [1-4]."
                    continue
        fi
    
            echo "your anwser is: $var"
            break
    done
    
    [root@localhost ~]# bash select.sh
    1) a
    2) b
    3) c
    4) d
    Enter a number: 1
    your anwser is: a
    

    FUNCTION 函数

    [root@localhost ~]# cat function.sh
    #!/bin/bash
    
    function my_print()
    {
            echo -e "------------------------"
            echo -e "hello world"
            echo -e "------------------------"
            return "127"
    }
    
    
    my_print
    echo $?
    
    [root@localhost ~]# bash function.sh
    ------------------------
    hello world
    ------------------------
    127
    

    参考文献:Linux鸟哥私房菜,Linux运维之道

  • 相关阅读:
    打酱油
    一个在线演示代码运行的网站
    java数据结构之枚举
    tomcat ; nginx ;mysql
    restful demo 演示; jquery min1.1;
    rest规范 ; restful 风格; gradel介绍 ; idea安装 ;
    jetty;tomcat;热部署
    web容器 web服务器 servlet/jsp容器 之间的区别和关系是什么?
    jetty;linux 目录结构
    servlet;jsp;cookies;session
  • 原文地址:https://www.cnblogs.com/LyShark/p/10221812.html
Copyright © 2011-2022 走看看