设为首页 收藏本站
查看: 2167|回复: 0

shell脚本编程的选择分支结构

[复制链接]

尚未签到

发表于 2018-8-23 06:33:45 | 显示全部楼层 |阅读模式
  选择执行结构:
  if语句单分支结构:如果条件为真,则执行then后的命令,否则,不做任何操作;
  if CONDITION ;then
  STATEMENT
  fi
  或
  if CONDITION ; then
  STATEMENT1
  STATEMENT2
  ...
  fi
  注意:想要执行then后面的STATEMENTS,前提条件是CONDITION部分为真;
  if语句的双分支结构:如果条件为真,就执行then后面的命令;否则就执行else后面的命令;
  if CONDITION ; then
  STATEMENT
  ...
  else
  STATEMENT
  ...
  fi
  位置参数变量:$1, $2, $3, ...
  特殊变量:
  $#:所有的位置参数的总数;
  $*:给出的所有位置参数的列表;当使用双引号引用时,整个参数列表被当做一个字符串;
  $@:给出的所有位置参数的列表;当时有双引号引用时,每个参数作为单独的字符串存在;
  $0:所执行的脚本文件自身的路径;
  /////练习:
  1.写一个脚本,给脚本传递用户名参数,判断参数数量是否合格;并且判断用户是否存在,如果存在,就显示相应信息;否则就创建之并为其设置密码;
  #!/bin/bash
  #
  if [ $# -ne 1 ] ; then
  echo "Only ONE USERNAME can be specified."
  exit 5
  fi

  if>  echo "$1 exists already."
  else
  useradd $1
  echo $1 | passwd --stdin $1 &> /dev/null
  echo "Create $1 successfully."
  fi
  2.写一个脚本:
  能够添加或删除用户账户,可以使用-a选项完成添加,使用-d选项完成删除用户;
  #!/bin/bash
  #
  if [ $# -ne 2 ] ; then
  echo "Usage: $(basename $0) -a Username | -d Username."
  exit 5
  fi
  if [ $1 == '-a' ] ; then

  if>  echo "$2 exists already."
  else
  useradd $2
  echo $2 | passwd --stdin $2 &> /dev/null
  echo "Create $2 successfully."
  fi
  fi
  if [ $1 == '-d' ] ; then

  if>  userdel -r $2
  echo "Delte $2 finished."
  else
  echo "User $2 does not exist."
  fi
  fi
  3.判断给出的文件大小是否大于100KB,如果大于100KB,就显示这是个大文件;否则就显示这是个小文件;
  #!/bin/bash
  #
  FILESIZE=$(wc -c < $1)
  if [ $FILESIZE -le 102400 ] ; then
  echo "Big file."
  else
  echo "Small file."
  fi
  4.判断给出的一个字符串是否为整数
  #!/bin/bash
  #
  if echo $1 | grep "^\$" &> /dev/null ; then
  echo "$1 is integer."
  else
  echo "$1 is not integer."
  fi
  if语句的多分支结构:
  首先判断CONDITION1是否为真,如果为真,则执行第一个then后面的语句;
  否则就判断CONDITION2是否为真,如果为真,就执行第二个then后面的语句;
  否则就判断CONDITION3是否为真,如果为真,就执行第三个then后面的语句...;
  如果所有的CONDITION都为假,就执行else后面的语句;
  if CONDITION1 ; then
  STATEMENT
  ...
  elif CONDITION2 ; then
  STATEMENT
  ...
  elif CONDITION3 ; then
  STATEMENT
  ...
  ...
  else
  STATEMENT
  ...
  fi
  编写一个脚本,要求:
  从/etc/passwd中UID和GID相同的用户中随机选择一个用户,判断该用户的类型:UID为0-->超级用户;UID在1-999之间-->系统用户;1000+登录用户;
  #!/bin/bash
  #
  LINES=$(egrep "\.*\1" /etc/passwd | wc -l)
  SEQUENCE=$[${RANDOM}%${LINES}+1]
  USERNAME=$(egrep "\.*\1" /etc/passwd | head -n ${SEQUENCE} | tail -1 | cut -d: -f1)
  USERID=$(egrep "\.*\1" /etc/passwd | head -n ${SEQUENCE} | tail -1 | cut -d: -f3)
  if [ $USERID -eq 0 ] ; then
  echo "$USERNAME is Super user."
  elif [ $USERID -ge 1000 ] ; then
  echo "$USERNAME is Login User."
  else
  echo "$USERNAME is System User."
  fi
  循环执行结构:
  将一段代码重复的执行0次、1次或多次;
  一个好的循环结构,必须要包括两个最重要的环节:
  进入循环的条件:
  开始循环时所满足的条件;
  退出循环的条件:
  循环结束所满足的条件
  for循环:
  1.遍历列表
  for VAR_NAME in LIST ; do
  循环体
  done
  VAR_NAME:任意指定的变量名称,变量的值是从LIST中取值并赋值的;
  循环体:一般来说是能够用到VAR_NAME的命令或命令的组合;如果循环体中没有包括VAR_NAME,则可能出现死循环;
  LIST的生成方式:
  1) 直接给出
  2) 纯整数列表
  eq:输出一个整数列表
  seq [FIRST [INCREMENT]] LAST
  3) 花括号展开
  {FIRST..LAST}
  4) 命令的执行结果的返回值
  5) GLOBBING
  6) 某些变量的引用:$@, $*
  for循环:
  进入循环的条件:LIST中有元素可以取用;
  退出循环的条件:LIST中以被取空,再无元素可用;
  for循环的特点:
  1.几乎不会出现死循环;
  2.在执行循环的过程中,需要将这个LIST载入内存;因此对于大列表来说可能会过多的消耗内存和CPU资源;
  示例:计算100以内所有整数的和;
  #!/bin/bash
  #
  read -t 5 -p "Please input a integer[0]: " INTEGER
  if [ -z $INTEGER ] ; then
  INTEGER=0
  fi
  if ! echo $INTEGER | grep -q "^\$" ; then
  echo "You must input an integer."
  exit 5
  fi
  for I in $(seq $INTEGER) ; do
  let SUM+=$I
  let SUM=$SUM+$I
  SUM=$[SUM+I]
  done
  echo $SUM
  2)写一个脚本,打印由*组成的倒置的等腰三角形;
  #!/bin/bash
  #
  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
  3)打印九九乘法表
  #!/bin/bash
  #
  for I in {1..9} ; do
  for J in $(seq $I) ; do
  echo -ne "$I*$J=$[I*J]\t"
  done
  echo
  done
  1X1=1 1X2=2 1X3=3 ... 1X9=9
  2X2=4 2X3=6 ... 2X9=18
  ...
  9X9=81
  注意:使用for循环嵌套的时候,外层for循环,控制行数的输出;内层for循环,控制列数的输出;
  2.控制变量
  for (( 表达式1; 表达式2; 表达式3 )); do 命令; done
  for (( 表达式1; 表达式2; 表达式3 )) ; do
  循环体
  done
  表达式1:为变量赋初始值;
  表达式2:循环的退出条件;
  表达式3:变量值的变化规律;
  #!/bin/bash
  for (( I=1; I shell toy
  回顾:
  字符串处理
  数组
  bash交互
  if
  for
  case分支选择结构:
  case 词 in [模式 [| 模式]...) 命令 ;;]... esac
  case 变量引用 in
  模式1)
  分支1
  ;;
  模式2)
  分支2
  ;;
  ...
  *)
  默认分支
  ;;
  esac
  模式(PATTERN):
  1.普通的文本字符
  2.globbing风格的通配符:
  *:任意长度任意字符
  ?:任意的单个字符
  []:范围内的任意单个字符
  [^]:范围外的任意单个字符
  3.|:或
  写一个脚本:
  提示用户输入信息,然后判断用户输入的信息是否合法;
  #!/bin/bash
  #
  read -p "Please make your choice[yes of no]: " CHOICE
  case $CHOICE in
  yes)
  echo "right."
  ;;
  no)
  echo "wrong."
  ;;
  *)
  echo "Unknown."
  ;;
  esac
  if CONDITION1 ; then
  STATEMENT
  elif CONDITION2 ; then
  STATEMENT
  elif CONDITION3 ; then
  STATEMENT
  ...
  else
  STATEMENT
  fi
  if的多分支结构和case的分支结构之间的区别:
  相同点:
  1.都是条件为真,执行对应分支的语句;条件为假,就不执行;
  2.都可以设置默认分支语句,即:所有条件都不匹配的时候,所执行的语句;
  不同点:
  1.if是根据命令的执行状态返回值来判断正确与否;case是根据变量的值的取值内容是否匹配模式来判断正确与否;
  2.case的每个分支都必须使用';;'结束;
  管理用户账户的脚本,第四版:利用case语句实现
  #!/bin/bash
  #
  if [ $# -lt 2 ] ; then
  echo "Usage: $(basename $0) -a User1,User2,...,UserN | -d User1,User2,...,UserN."
  exit 5
  fi
  case $1 in
  -a)
  for I in $(echo $2 | tr ',' ' ') ; do

  if>  echo "$I exists already."
  else
  useradd $I
  echo $I | passwd --stdin $I &> /dev/null
  echo "Create $I successfully."
  fi
  done
  ;;
  -d)
  for J in $(echo $2 | tr ',' ' ') ; do

  if>  userdel -r $J
  echo "Delte $J finished."
  else
  echo "User $J does not exist."
  fi
  done
  ;;
  *)
  echo "Usage: $(basename $0) -a User1,User2,...,UserN | -d User1,User2,...,UserN."
  exit 6
  esac
  while
  while 命令; do 命令; done
  while CONDITION ; do
  循环体
  done
  进入循环条件:CONDITION一直为真;
  退出循环条件:CONDITION为假;
  until
  until 命令; do 命令; done
  until CONDITION ; do
  循环体
  done
  进入循环条件:CONDITION一直为假;
  退出循环条件:CONDITION为真;
  while CONDITION ; do CMD ; done
  相当于
  until ! CONDITION ; do CMD ; done
  注意:对于while和until两个循环结构来讲,如果要实施变量增量操作,必须手动给出;
  利用while和until循环结构,计算100以内所有整数的和;
  #!/bin/bash
  #
  declare -i I=1
  while [ $I -le 100 ] ; do
  let SUM+=$I
  let I++
  done
  echo $SUM
  #!/bin/bash
  #
  declare -i I=1
  until [ $I -gt 100 ] ; do
  let SUM+=$I
  let I++
  done
  echo $SUM
  循环控制语句:
  continue
  break
  continue:
  continue [n]
  提前结束第n层的本次循环,直接进入下一轮条件判断,若符合循环进入条件,则开启下一轮循环;
  break:
  break [n]
  提前技术第n层循环;不再继续后续循环;
  无限循环用法:
  while true ; do
  循环体
  done
  until false ; do
  循环体
  done
  在此类的循环结构中,必须适当的使用continue和break,以保证循环不会一直持续下去;
  能够实现遍历功能的while循环和until循环;
  while read LINES ; do
  循环体
  done < /PATH/FROM/SOMEFILE
  until ! read LINES ; do
  循环体
  done < /PATH/FROM/SOMEFILE
  select
  select循环主要用于创建一个菜单式列表,供用户进行选择;
  列表是按照数字顺序排列的,我们只要选择数字即可;
  一般来讲,select与case一起使用;
  select是一个无限循环结构,因此,必须在循环体中使用break命令以退出循环,或者可以使用exit命令直接终止脚本运行;
  select NAME [in 词语 ... ;] do 命令; done
  select NAME [in LIST] ; do
  命令
  done
  总结:
  shell脚本编程语言:
  过程式编程语言
  顺序:主体结构
  选择:
  if
  单
  双
  多
  case
  循环
  for
  遍历列表:
  控制变量
  while
  until
  select
  编写个shell脚本将/usr/local/test目录下大于100k的文件转移到/tmp目录下。
  #!/bin/bash
  #
  FPATH="/usr/local/test"
  DEST=/tmp
  for i in $FPATH/* ; do
  if [ -f $i ] ; then
  if [ $(wc -c < $i) -gt 102400 ] ; then
  ls -l $i
  fi
  fi
  done
  回顾:
  case
  while
  until
  continue
  break
  select
  systemV风格的服务管理脚本:
  给脚本传递一些参数:start, stop, restart, status
  myservice.sh
  #!/bin/bash
  #
  lockfile="/var/lock/subsys/$(basename $0)"
  case $1 in
  start)
  if [ -f $lockfile ] ; then
  echo "服务已经启动...."
  else
  touch $lockfile
  echo "服务正在启动...."
  fi
  ;;
  stop)
  if [ -f $lockfile ] ; then
  rm -f $lockfile
  echo "服务已经停止...."
  else
  echo "服务尚未启动..."
  fi
  ;;
  restart)
  if [ -f $lockfile ] ; then
  rm -f $lockfile
  echo "服务已经停止...."
  else
  echo "服务尚未启动..."
  fi
  if [ -f $lockfile ] ; then
  echo "服务已经启动...."
  else
  touch $lockfile
  echo "服务正在启动...."
  fi
  ;;
  status)
  if [ -f $lockfile ] ; then
  echo "服务已经启动...."
  else
  echo "服务已经停止...."
  fi
  ;;
  *)
  echo "Usage: $(basename $0) start|stop|restart|status"
  exit 5
  ;;
  esac
  把那些在脚本中重复出现并且没有任何改变的代码,封装起来,在适当的场景中调用执行;
  程序员将这种被封装起来的代码称为功能体,或者叫模块;
  function —— 函数
  在shell脚本编程中,函数是由若干条shell命令组成的语句块;通常用于代码重用和模块化封装;
  函数里面的内容和shell程序形式上是一致的;不同之处就是,shell代码可以直接被执行;而函数中的内容,不能独立执行,只有被调用的时候才执行;
  函数是在shell程序的当前shell中运行的;
  bash
  bash script_file
  function
  定义函数:
  函数是由两部分组成:
  函数名称 + 函数体(能够实现独立功能的shell语句块)
  语法一:
  function func_name {
  函数体
  }
  语法二:
  func_name() {
  函数体
  }
  注意:函数名和()之间不能加空白字符;
  注意:函数可以在交互式环境下定义,也可以在脚本中定义;
  函数的使用
  函数在定义的时候,其函数体中包含的所有命令均不会被执行;只有函数被调用的时候,才会执行其中的命令语句;
  调用方式:通过直接给出函数名称的方式调用;
  有很多的函数是存放于专门用于保存函数的文件中;如果想要调用这样的文件中保存的函数,使用source命令(.)加载文件,然后再以直接给出函数名称的方式调用函数;
  使用set命令可以查看所有当前shell中生效的函数;
  使用unset命令可以撤销已经定义的函数;
  函数的返回值:
  两种返回值:
  函数的执行结果的返回值:
  1.在函数体中使用了echo或printf命令输出的结果;
  2.在函数体中某些命令输出的结果;
  函数的状态返回值:
  1.函数中最后一条命令的执行状态返回值;
  2.自定义退出状态码:
  return [n]
  n:0-255 (1 2 127尽可能不使用)
  0: 表示无错误返回
  1-255:有错误返回
  注意:只要函数在执行时,遇到了return命令,不管函数中的命令语句是否全部执行完成,立刻退出函数;
  函数的生命周期:
  从被调用开始,到遇到return命令或全部的语句执行完成为止;
  函数的实参
  在函数体中,可以使用$1,$2,..位置变量为函数提供参数;还可以使用$*或$@的方式引用所有位置参数;还可以使用$#计算为函数传递的参数个数;
  在调用函数的时候,直接在函数名称后面以空白字符分隔多个参数即可;比如:func_name arg1 arg2 ...
  传递给函数参数的位置参数,是调用函数的时候,函数名称后面的以空白字符分隔的字符串序列;跟脚本的位置参数不是一回事;
  变量:
  shell中的变量为弱变量
  1.无需事先声明
  2.无需指定变量类型,默认为字符型
  变量分类:
  环境变量:
  当前shell及子shell
  本地变量:
  当前shell
  局部变量:
  local VAR_NAME=VALUE
  当前函数体
  位置变量
  特殊变量
  建议:手动撤销自己定义或声明的所有变量;
  函数的递归调用
  简单来说,就是在函数体中调用函数自身;
  阶乘:
  N!=N*(N-1)!=N*(N-1)*(N-2)!=...=N*(N-1)*(N-2)*...*2*1
  shell代码:
  #!/bin/bash
  # Author: Tianyu.Zhao
  #
  fact(){
  if [ $1 -eq 0 ] || [ $1 -eq 1 ] ; then
  echo 1
  else
  echo "$[$1*$(fact $[$1-1])]"
  fi
  }
  echo -n "$1!="
  fact $1
  斐波那契数列(黄金分隔数列):
  1 1 2 3 5 8 13 21 34 55 ...
  假设兔子出生一个月之后才会有繁殖能力:
  N=N-1 + N-2
  shell代码:
  #!/bin/bash
  # Author: Tianyu.Zhao
  #
  fabonacci(){
  if [ $1 -eq 1 ] ; then
  echo 1
  elif [ $1 -eq 2 ] ; then
  echo 1
  else
  echo $[$(fabonacci $[$1-1])+$(fabonacci $[$1-2])]
  fi
  }
  #列出所有的斐波那契数列的项
  for I in `seq 0 $1` ; do
  fabonacci $I
  done
  汉诺塔(又称河内塔)问题是源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
  利用函数,实现N片盘的汉诺塔的移动步骤
  #!/bin/bash
  # Author: Tianyu.Zhao
  #
  step=0
  move(){
  let step++
  echo "$step:  move disk $1 $2 -----> $3"
  }
  hanoi(){
  if [ $1 -eq 1 ];then
  move  $1 $2 $4
  else
  hanoi "$[$1-1]" $2 $4 $3
  move $1 $2 $4
  hanoi "$[$1-1]" $3 $2 $4
  fi
  }
  hanoi $1 A B C
  文件abc.txt的内容如下:
  2,3,4,5,6
  B,c,d,e,f
  6,7,8,9,10
  f,g,h,i,j
  写一个脚本,利用任一循环结构,输出每一行的第二个和第四个字符(以逗号分隔)
  回顾:
  shell脚本编程之函数
  练习:
  写一个脚本:
  1.允许用户通过命令行传递参数,实现用户账户的管理;
  2.如果给出-a|--add选项,就创建该选项后面的用户账户;
  3.如果给出-d|--del选项,就删除该选项后面的用户账户;
  4.如果用户给出-v|--verbose选项, 就显示删除或创建用户的信息;
  5.如果用户给出-h|--help选项,就显示帮助信息,并且以0作为退出状态码退出脚本的运行;
  6.如果用户给出其他选项,显示帮助信息,并以5作为退出状态码鬼畜脚本的运行;
  #!/bin/bash
  #Author: Link
  #Description: administrate users
  #5: no enough args
  #6: error args
  #
  DEBUG=0
  ADDUSER=0
  DEUSER=0
  usage(){
  echo "Usage: $(basename $0) -a|--add user1,user2,... | -d|--del user1,user2,... | [-v|-verbose] | [-h|--help]"
  echo
  echo "Options: "
  echo -e "  -a, --add\vCreate user from list."
  echo -e "  -d, --del\vDelete user from list."
  echo -e "  -v, --verbose\vDisplay infomation for your operating."
  echo -e "  -h, --help\vDisplay this menu."
  }
  createuser() {
  ADDUSER_LIST=$(echo $1 | tr ',' ' ')
  for I in $ADDUSER_LIST ; do

  if>  [ $DEBUG -eq 1 ] && echo "$I exists."
  else
  useradd $I &> /dev/null
  echo $I | passwd --stdin $I &> /dev/null
  [ $DEBUG -eq 1 ] && echo "Create $I successfully."
  fi
  done
  }
  deleteuser() {
  DELUSER_LIST=$(echo $1 | tr ',' ' ')
  for J in $DELUSER_LIST ; do

  if>  userdel -r $J &> /dev/null
  [ $DEBUG -eq 1 ] && echo "Delete $J finished."
  else
  [ $DEBUG -eq 1 ] && echo "$I not exists."
  fi
  done
  }
  if [ $# -le 0 ] ; then
  usage
  exit 5
  fi
  while [ $# -ne 0 ] ; do
  case $1 in
  -h|--help)
  usage
  exit
  ;;
  -v|--verbose)
  DEBUG=1
  shift
  ;;
  -a|--add)
  ADDUSER=1
  ALIST=$2
  shift 2
  ;;
  -d|--del)
  DELUSER=1
  DLIST=$2
  shift 2
  ;;
  *)
  usage
  exit 6
  ;;
  esac
  done
  if [ $ADDUSER -eq 1 ] ; then
  createuser $ALIST
  fi
  if [ $DELUSER -eq 1 ] ; then
  deleteuser $DLIST
  fi
  总结:
  写一个脚本的步骤:
  1.构建程序主体
  默认是顺序执行结构
  根据需求添加相应的选择结构和循环结构
  2.确定完成某功能所需的命令
  3.调试(bash -x /PATH/TO/SCRIPT_FILE)
  4.写明帮助信息


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-555247-1-1.html 上篇帖子: shell多线程实现从ftp下载数据 下篇帖子: linux shell简单脚本分享
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表