bash脚本编程之判断和循环

bash脚本编程之判断和循环

     变量:
      特性:一个变量中只能存储一个数值;

     数组:能够容纳多个数组元素的连续的内存空间;

      1)稀疏数组:
      2)稠密数组: 

    数组元素:数组中任何一个存放数据的存储单元,其作用相当于一个变量;

    数组元素的标识:

      索引数组标识:所有的数组元素都是使用数字编号的;
      通常数字标号是从0开始的,即:0,1,2....

    关联数组标识:所有的数组元素都可以使用名称(字符串)来标识;
      注意:bash4.0以上版本才有可能支持关联数组;

   数组声明定义:
      1.declare命令:
         -a to make NAMEs indexed arrays (if supported)
           将其后的变量名称声明为索引数组;declare -a names=([0]='z'[1]='w' [2]='1')
         -A to make NAMEs associative arrays (if supported)
           将其后的变量名称声明为关联数组;declare -a names=( "z" "w" "l" )

     2.直接使用变量赋值的方式:
         定义稠密的索引数组
         ARRAY-NAME=(“VALUE1” “VALUE2”....)

         定义稀疏数组:
          ARRAY-NAME=([0]=“VALUE1” [1]=“VALUE2”....)

         定义关联数组:
           ARRAY-NAME=(INDEX_name1='VALUE1' INDEX_VALUE2='VALUE2'....)

     3.分别定义数组元素:
         ARRAY_NAME[0]='VALUE' 
         ARRAY_NAME[1]='VALUE'      
         ARRAY_NAME[2]='VALUE'
         .......

  引用数组元素的方式:
        ${ARRAY_NAME[INDEX]} 
        注意:在引用数组元素时,没人给出索引号,默认编号为”0“,即显示第一个数组元素的数值;

  引用整个数组中所有元素:
        ${ARRAY_NAME[*]}或 ${ARRAY_NAME[@]} 

  引用整个数组的所有元素的索引号:
        ${!ARRAY_NAME[*]}或 ${!ARRAY_NAME[@]}

  查看数组中的元素个数(数组长度):
       ${#ARRAY_NAME[*]}或 ${#ARRAY_NAME[@]}

  数组切片:
        ${ARRAY_NAME[*]:offset}
          //显示包括offste数值所对表示的位置的元素极其后所有的元素;

        ${ARRAY_NAME[*]:offset:number}
          //显示数组中包括offset数值所对应表示的位置的元素及其后number个元素;

  数组撤销:
        unset ARRAY_NAME

  RANDOM变量:
        随机数变量:0-32767,整数值;

        从熵池中取随机数;

        熵池:
        /dev/random
          两次敲击键盘的时间间隔;
          两次IO的时间间隔;
          ...
        /dev/urandom:伪熵池
          利用应用程序计算得到的随机数;
                        [root@localhost ~]# echo $RANDOM
         25570
         [root@localhost ~]# echo $RANDOM
         8882
         [root@localhost ~]# echo $RANDOM
         2373
        [root@localhost ~]# echo $RANDOM
        4870
       [root@localhost ~]# echo $RANDOM
        3895
       [root@localhost ~]# echo $RANDOM
        8353
      [root@localhost ~]# echo $RANDOM
       14099

 bash脚本编程的结构:
   bash脚本编程语言:
        脚本类语言
        解释型语言
        过程式编程语言

      过程式编程语言结构:
       顺序执行结构:默认
         从上而下,自左而右地执行所有的语句(命令);

       选择执行结构:
         当条件满足或不足时,才会执行对应的语句(命令);

       循环执行结构:
         重复执行某段语句(命令);    

   bash脚本编程语中也具有上述结构;
        顺序执行结构:默认

       选择执行结构:
        根据给定条件逻辑判断结果或根据某个可选取的取值范围,进而选择某个分支结构中的命令语句予以执行的方式;
       if:
         选择执行结构的标准,根据条件的逻辑判断结果选择执行的语句内容;
       case:
         选择执行结构的标准,根据符合某特定范围的取值标准选择执行的语句内容;

       循环执行结构:
        对于特定语句内容 ,重复执行0,1,多次;

       for:以遍历列表的方式进行循环;
       while:根据给定条件的逻辑判断结果进行循环,逻辑判断结果为真,循环,否则,停止循环;   
       until:根据给定条件的逻辑判断结果进行循环,逻辑判断结果为假,循环,否则,停止循环;
       select:死循环,即没有默认退出条件的循环;利用循环提供一个可选择的列表;

 bash脚本的执行结构之if选择执行结构:
      if语句:if - if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi

    if语句的单分支结构:
        if - if COMMANDS; then COMMANDS; fi

        注意:是否会执行then后面的命令,取决于if后面的命令的执行状态返回值:
            1.如果其返回值为真,则执行then后面的命令;
            2.如果其返回值为假,则不执行then后面的命令;

      建议在脚本中的书写格式:
       if CONDITION ; then
         statement
          ...
       fi 

       或

       if  CONDITION

       then

         STATEMENT
         ....
       fi

       if语句的双分支结构:
        if - if COMMANDS; then COMMANDS; else COMMANDS; fi

        注意:是否执行then后的命令或else后的命令,取决于if后的命令执行状态的返回值;
        1.如果返回值为真,则执行then后的命令;
        2.如果为假,则执行else后的命令;

       if语句的多分支结构:

         if - if COMMANDS; then COMMANDS; else COMMANDS; fi

        注意:是否执行then后的命令或else后的命令,取决于if后的命令执行状态的返回值或else后的命令执行状态返回值;

        1.首先判断if后的命令的状态返回值是否为真,为真就执行then后的语句;如果为假,就继续判断第一个elif后的命令
          执行状态返回值;
        2.第一个elif后的命令执行状态返回值为真,就执行第一个elif语句中then后的命令,否则,就继续判断第二个elif后的
          执行状态返回值;
       3.以此类推,会判断每个elif后面的命令的执行状态返回值是否为真;如果所有的if和elif后面的命令的执行状态返回值均为假,则执行else后面的语句;

        建议在脚本中的书写格式:
            if CONDITION1 ; then
                STATEMENT
                ...
            elif CONDITION2 ; then
                STATEMENT
                ...
            elif CONDITION3 ; then
                STATEMENT
                ...
            ...
            else
                STATEMENT
                ...
            fi
            或
            if CONDITION
            then
                STATEMENT
                ...
            elif CONDITION2 ; then
                STATEMENT
                ...
            elif CONDITION3 ; then
                STATEMENT
                ...
            ...
            else
                STATEMENT
                ...
            fi

       注意:if的多分支结构,使用场景不多,而且有时候,可以使用嵌套的多分支或双分支if结构代替if多分支结构;

       嵌套的if结构
         if CONDITION1 ; then
            if CONDITION2 ; then
               if CONDITION3 ; then
                STATEMENT
                ...

               else
                STATEMENT
                ...

            else
             STATEMENT
              ...
              fi

         else
          STATEMENT
          ...
          fi

     COMMAND1 && COMMAND2 || COMMAND3

    示例:
      写脚本,判断某个用户的默认登录shell是否为/bin/bash

      #!/bin/bash
      y=$(cut -d: -f 1 /etc/shadow | sort -R | head -1)
      w=$(egrep "^$y\>" /etc/passwd | cut -d: -f 7)
      if [ "$w"=="/bin/bash" ] ; then
          echo "${y}'s login shell is /bin/bash."
      else
          echo "${y}'s login shell is ${w}"
      fi

      unset y w

     bash脚本编程之用户交互使用:
       位置参数变量:
       $0:命令的本身,对于脚本而言,就是该脚本的路径;
       $1,$2,....$N:脚本后面通过命令行给脚本传递的命令行参数;
         N>9时,引用该位置变量时需要加{},即${10}

      特殊变量:
      $@:给出的所有位置的参数的列表,当使用双引号时,每个参数作为单独的字符串存在;
      $*:给出的所有位置的参数的列表,当使用双引号时,每个参数作为单独的字符串存在;
      $#:表示除去$0之外,整个命令行中有多少个参数;

     read命令:
       read [-ers] [-a 数组] [-d 分隔符] [-i 缓冲区文字] [-n 读取字符数] 
            [-N 读取字符数] [-p 提示符] [-t 超时] [-u 文件描述符] [名称 ...]

        -a array:定义数组(索引数组);
        -p prompt:给用户输出提示信息;
        -t timeout:用户输入的超时时间;
         name :变量或数组的名称;如果省略此内容,bash会将read读到的信息直接保存到内置的名为REPLAY变量中;

     注意:
        Linux思想之一:尽量不与用户交互;

        在使用read命令时,通常会使用-t选项来指定与用户的交互时间,一旦超过预定时间,脚本中后续的命令内容
        会自动被执行;因此,通常需要在后面判断通过read赋值的变量值是否为空,如果为空,可能为该变量提供默认值;

        read -t 5 VAR1
          [ -z $VAR1 ] && VAR1=value1

   管理用户脚本:
   脚本可以接受两个参数,第一个参数为-a或-d,第二个参数为用户名;如果第一个参数是-a,则创建其后面参数命名的用户;如果第一个参数为-d,则删除其后面参       数命名的用户;

     #!/bin/bash
     #
    if [ $# -ne 2 ] ; then
    echo "Make sure provide TWO arguments."
      exit 5
      fi

    if [ $1 == '-a' ] ; then
      if ! id $2 &> /dev/null ; then
        useradd $2 &> /dev/null
        echo $2 | passwd --stdin $2 &> /dev/null
        echo "User $2 created succesfully and password changed to it's username."
      else
        echo "$2 exists already."
      fi
    elif [ $1 == '-d' ] ; then
      if id $2 &> /dev/null ; then
        userdel -r $2 &> /dev/null
        echo "User $2 delete finished."
      else
        echo "$2 does not exist yet."
      fi
      else
        echo "Usage: $(basename $0) -a USERNAME | -d USERNAME"
      exit 6
    fi

改进版:使用read命令;
#!/bin/bash
#
if [ $# -ne 1 ] ; then
echo "Make sure provide ONE argument."
exit 5
fi

if [ $1 == '-a' ] ; then
read -p "Please input a username for creating: " USERNAME
if ! id $USERNAME &> /dev/null ; then
useradd $USERNAME &> /dev/null
echo $USERNAME | passwd --stdin $USERNAME &> /dev/null
echo "User $USERNAME created succesfully and password changed to it's username."
else
echo "$USERNAME exists already."
fi
elif [ $1 == '-d' ] ; then
read -p "Please input a username for deleting: " USERNAME
read -t 5 -p "confirm? Input 'yes' to continue: " CHOICE
[ -z $CHOICE ] && CHOICE='no'

if [ $CHOICE == 'yes' ] ; then
if id $USERNAME &> /dev/null ; then
userdel -r $USERNAME &> /dev/null
echo "User $USERNAME delete finished."
else
echo "$USERNAME does not exist yet."
fi
else
echo
echo "$USERNAME is not deleted."
fi
else
echo "Usage: $(basename $0) { -a | -d }"
exit 6
fi

写脚本解决问题:
1.判断用户通过命令行给的一个参数是否为整数。

#!/bin/bash

if [ $# -ne 1 ] ; then
echo "Make sure provide ONE digit."
exit 5
fi

if [[ $1 =~ ^[[:digit:]]+$ ]] ; then
echo "$1 is a pure digit."
else
echo "$1 is not a digit."
fi

    循环执行结构:
       循环:将某一段代码或命令重复执行0,1或多次;

       一个好的循环结构,必须要包括两个重要的环节:
        1.进入循环的条件:
          在符合要求或满足条件时才开始循环;

        2.退出循环条件:
          达到某个要求或符号某个条件时需要结束或终止循环的执行;

    for循环:
       1.遍历列表的循环:
         for 名称 [in 词语 ... ] ; do 命令; done
         为列表中的每个成员执行命令。

         建议在脚本中的书写格式:
         for VAR_NAME in LIST ; do
           循环体
         done
         或
         for VAR_NAME in LIST 
         do
            循环体
         done

         注意:
         VAR_NAME:任意指定的变量名称,变量的值是从LIST中遍历获取的各个元素;
         LIST:for循环需要遍历的列表,可以通过如下方式生成列表:
            1.直接给出列表;
            2.纯整数列表:
              1):花括号展开:
                   {FIRSTNUM..LASTNUM}

              2):seq命令
                    seq [OPTION]... LAST  seq 10

                    seq [OPTION]... FIRST LAST  seq 2 6

                    seq [OPTION]... FIRST INCREMENT LAST   seq 0 2 20

           3.花括号展开
                   {FIRST..LAST}

           4.命令的执行结果:
             ls /etc

           5.GLOBBING通配符

           6.某些特殊变量的值:
             $*,$@

          循环体:

            一般来说,循环体中应该包括能够用到VAR_NAME变量的值的命令或命令的组合;如果循环体中的命令没有用到
            VAR_NAME变量的值的话,列表的元素的个数就是此次for循环的次数;

            #!/bin/bash
            for i in {1..50} ; do 
            sum=$[sum+i]
            done
            echo "$sum" 

       例子:给脚本传递三个整数,要求:
1) 如果用户传递过来的不是三个参数,报告正确用法;
2) 如果三个参数中有非纯数字字符串,报告错误并提示用户输入数字;
3) 从三个整数中的选出最大数和最小数,并显示出来;
4) 不能使用sort命令等排序;
[root@localhost ~]# vim a.sh
#!/bin/bash
#
if [ $# -ne 3 ] ; then
   echo " please provide three argument"
   exit 5
fi
if [[ $1 =~ [^[:digit:]] ]]||[[ $2 =~ [^[:digit:]] ]] ||[[ $3 =~ [^[:digit:]] ]] ; then
   echo "exist error"
fi
if [ $1 -ge $2 ] ; then
    if [ $1 -ge $3 ] ; then
       echo "the largest is $1"
    fi
fi
if [ $2 -ge $1 ] ; then
    if [ $1 -ge $3 ] ; then
      echo "the largest is $2"
    fi
fi
if [ $3 -ge $1 ] ; then
   if [ $3 -ge $2 ] ; then
     echo "the largest is $3"
   fi
fi
if [ $1 -le $2 ] ; then
   if [ $1 -le $3 ] ; then
     echo "the smallest is $1"
   fi
fi
if [ $2 -le $1 ] ; then
   if [ $2 -le $3 ] ; then
     echo "the smallest is $3"
   fi
fi
if [ $3 -le $1 ] ; then
  if [ $3 -le $2 ] ; then
    echo "the largest is $3"
  fi
fi

结果:
 [root@localhost ~]# bash a.sh  12  13 14
 the largest is 14
 the smallest is 12

例:给脚本传递一个整数,分别计算该整数以内所有偶数之和以及奇数之和。
[root@localhost ~]# vim q.sh
#!/bin/bash
declare i sum=0 sum1
if [[ $1 =~ [^[:digit:]] ]] ;then
echo "$1should be an integer"
exit 5
fi
if [ "$1" -eq 1 ] ; then
echo "奇数和为1"
exit 5
fi
if [ "$1" -eq 2 ] ; then
echo "偶数和为2"
exit 5
fi

for i in $(seq 1 2 $1) ; do
sum=$[sum+i]

done
echo "奇数和为$sum"
for i in $(seq 2  2 $1 ) ; do
sum1=$[sum1+i]

done
echo "偶数的和为$sum1"

结果:[root@localhost ~]# bash q.sh 3
奇数和为4
偶数的和为2
[root@localhost ~]# bash q.sh 5
奇数和为9
偶数的和为6

        例:      
8.利用RANDOM变量随机生成十个数字,显示出这十个数字,并显示出其中的最大值和最小值。

[root@localhost ~]# vim 000

#!/bin/bash

touch ytc
for i in $( seq 1 10 ) ; do
echo $RANDOM &>> ytc
done
sort -n ytc| head -1
sort -n ytc| tail -1
rm -r ytc

结果:
[root@localhost ~]# bash 000
7119
28639
[root@localhost ~]# bash 000
412
31953

 例:给脚本传递一个数字作为行总数,分别打印由*组成的最小锐角朝上和朝下的等腰三角形以及菱形。
  角朝下 

[root@localhost ~]# vim 9
#!/bin/bash

if [ $# -ne 1 ] ; then
echo " usage: $(basename $0) integer"
exit 5
fi

if [[ $1 =~ [^[:digit:]] ]] ; then
echo " usage: $(basename $0) integer"
exit 5
fi

linenum=$1
for i in $(seq $linenum) ; do
for j in $(seq $[i-1 ]); do
echo -n " "
done
for k in $(seq $[2(linenum-i)+1 ]) ; do
echo -n "
"
done
echo
done

结果:[root@localhost ~]# bash 9 8





*******
 *****
  ***
   *

角朝上:
[root@localhost ~]# vim 10
#!/bin/bash

if [ $# -ne 1 ] ; then
echo "Usage: $(basename $0) INTEGER"
exit 5
fi

if [[ $1 =~ [^[:digit:]] ]] ; then
echo "Usage: $(basename $0) INTEGER"
exit 6
fi

linenum=$1
for i in $( seq $linenum) ; do
for j in $( seq $[linenum-i]) ; do
echo -n " "
done
for k in $(seq $[2i-1]) ; do
echo -n "
"
done
echo
done

结果:
[root@localhost ~]# bash 10 8
*


 *****
*******




菱形:
[root@localhost ~]# vim 11
#!/bin/bash

if [ $# -ne 2 ] ; then
echo "Usage: $(basename $0) INTEGER"
exit 5
fi

if [[ $1 =~ [^[:digit:]] ]] ; then
echo "Usage: $(basename $0) INTEGER"
exit 6
fi

linenum=$1
for i in $( seq $linenum) ; do
for j in $( seq $[linenum-i]) ; do
echo -n " "
done
for k in $(seq $[2i-1]) ; do
echo -n "
"
done
echo
done

linenum=$2

for i in $(seq $linenum) ; do
for j in $(seq $[i ]); do
echo -n " "
done
for k in $(seq $[2(linenum-i)+1 ]) ; do
echo -n "
"
done
echo
done

结果:
[root@localhost ~]# bash 11 8 7
*


 *****
*******







*******
 *****
  ***
   *

例:分别打印顺序和旋转的九九乘法表。
1)顺序的九九乘法表是正常的九九乘法表;
[root@localhost ~]# vim 8
#!/bin/bash

  for i in {1..9} ; do
     for j in $(seq $i) ; do
     echo -ne "$i×$j=$[i*j]\t"
     done
     echo
  done

   2)旋转的九九乘法表是第一行是1×1=1 1×2=2 1×3=3 1×4=4 ... 1×9=9; 第二行是2×2=4 2×3=6 2×4=8 ... 2×9=18; ... 第九行是9×9=81;
 [root@localhost ~]# vim 7
  #!/bin/bash

  for i in {1..9} ; do
     for j in $(seq $i 9) ; do
     echo -ne "$i×$j=$[i*j]\t"
     done
     echo
  done

  结果:
  [root@localhost ~]# bash 7

1×1=1 1×2=2 1×3=3 1×4=4 1×5=5 1×6=6 1×7=7 1×8=8 1×9=9
2×2=4 2×3=6 2×4=8 2×5=10 2×6=12 2×7=14 2×8=16 2×9=18
3×3=9 3×4=12 3×5=15 3×6=18 3×7=21 3×8=24 3×9=27
4×4=16 4×5=20 4×6=24 4×7=28 4×8=32 4×9=36
5×5=25 5×6=30 5×7=35 5×8=40 5×9=45
6×6=36 6×7=42 6×8=48 6×9=54
7×7=49 7×8=56 7×9=63
8×8=64 8×9=72
9×9=81

     总结:
         1.进入循环的条件:LIST中还有未被取尽的元素;
         2.退出循环的条件:LIST中的元素被取尽;
         3.for循环几乎不会出现死循环;
         4.在执行循环的过程中,需要将整个LIST载入内存,因此对于大列表来说,可能会消耗较多的内存及CPU资源;

编程思想:
将人类的自然语言转换成程序的代码语言的方式;

DevOPS

不会开发的运维是没有出路的。

流程图

如果 a大于3, 那么
创建一个用户
fi

转载于:https://blog.51cto.com/yuantianchi/2046509

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值