bash脚本编程

case选择分支结构
case 词 in [模式 [| 模式]...) 命令 ;;]... esac
  在脚本中使用的case结构:
    case $(VAR-NAME) in
      PATTERN1)
        COMMAND
        ...
        ;;
      PATTERN2)
        COMMAND
        ...
        ;;
      ...
    esac

PATTERN可以是下列几类字符:
    1.普通文本字符
    2.GLOBBING风格的通配符
      *:任意长度的任意字符
      ?:任意单个字符
      []:指定范围内的任意单个字符
      [^]:指定范围以外的任意单个字符
    3. |  或字符

eg: 写一个脚本:
    判断用户利用脚本删除某文件时,是否执行删除操作;
#!/bin/bash
#
if [ -e $1 ] ; then
  echo -e "\033[5;1;31mDanger!\033[1;31mAre you sure to delete it? [yes or no] \033[0m"
  read -t 5 CHOICE
  [ -z $CHOICE ] && CHOICE=no
  case $CHOICE in
    yes)
      rm -rf $1
      ;;
    no)
      echo "Right choice."
      ;;
  esac
else
  echo "$1 does not exist."
fi

#!/bin/bash
#
if [ -e $1 ] ; then
  echo -e "\033[5;1;31mDanger!\033[0m\033[1;31mAre you sure to delete it? [yes or no] \033[0m"
  read -t 5 CHOICE
  [ -z $CHOICE ] && CHOICE=no
  if [ "$CHOICE" == 'yes' ] ; then
    rm -rf $1
  elif [ "$CHOICE" == 'no' ] ; then
    echo "Right choice."
  fi
else
  echo "$1 does not exist."
fi

if的多分支结构和case的选择分支结构的异同:
  相同点:
    1.判断的条件为真时才会执行对应分支中的语句;条件为假则不执行;
    2.都可以设置默认分支语句;即:所有给定的条件的判断结果都为假时,执行的语句;
  不同点:
    1.if是根据命令的执行状态返回值的真假来判断是否执行某个分支中的语句;
      case是根据某个变量中保存的值与指定模式匹配的结果为真假来判断是否执行某个分支中的语句;
    2.if的每个分支中无需单独的结束标记,case的每个分支都必须以;;结束;

编写管理用户账户的脚本,第四版,利用case语句+for循环,同时接受创建和删除用户的操作;

#!/bin/bash
#
if [ $# -lt 1 ] ; then
  echo -e "Usage: $(basename $0) options... USERLIST\n"
  echo -e "  Options: "
  echo -e "    -a, --add: \vAdd some users from USERLIST."
  echo -e "    -d, --delete: \vDelete some users from USERLIST."
  echo -e "    -h, --help: \vPrint help informationn."
  echo -e "    -v, --verbose: \vPrint more informationn about manage users."
  echo
  echo -e "  USERLIST FORMAT: "
  echo -e "    USERNAME1,USERNAME2,...,USERNAMEN"
  exit 5
fi

ADDUSER=0
DELUSER=0
DEBUG=0

for I in $(seq $#) ; do
  if [ $# -ne 0 ] ;then
    case $1 in
      -h|--help)
        echo -e "Usage: $(basename $0) options... USERLIST\n"
        echo -e "  Options: "
        echo -e "    -a, --add: \vAdd some users from USERLIST"
        echo -e "    -d, --delete: \vDelete some users from USERLIST"
        echo -e "    -h, --help: \vPrint help informationn"
        echo -e "    -v, --verbose: \vPrint more informationn about manage users."
        echo
        echo -e "  USERLIST FORMAT: "
        echo -e "    USERNAME1,USERNAME2,...,USERNAMEN"
        exit 0
        ;;
      -v|--verbose)
        DEBUG=1
        shift
        ;;
      -a|--add)
        ADDUSERLIST=$2
        ADDUSER=1
        shift 2
        ;;
      -d|--delete)
        DELUSERLIST=$2
        DELUSER=1
        shift 2
        ;;
      *)
        echo -e "Usage: $(basename $0) options... USERLIST\n"
        echo -e "  Options: "
        echo -e "    -a, --add: \vAdd some users from USERLIST"
        echo -e "    -d, --delete: \vDelete some users from USERLIST"
        echo -e "    -h, --help: \vPrint help informationn"
        echo -e "    -v, --verbose: \vPrint more informationn about manage users."
        echo
        echo -e "  USERLIST FORMAT: "
        echo -e "    USERNAME1,USERNAME2,...,USERNAMEN"
        exit 6
        ;;
    esac
  fi
done

if [ $ADDUSER -eq 1 ] ; then
  for J in $(echo $ADDUSERLIST | tr ',' ' ') ; do
    if ! id $J &> /dev/null ; then
      useradd $J &> /dev/null
      echo $J | passwd --stdin $J &> /dev/null
      [ $DEBUG -eq 1 ] && echo "Create user $J successfully."
    else
      echo "$J exist already."
    fi
  done
fi

if [ $DELUSER -eq 1 ] ; then
  for J in $(echo $DELUSERLIST | tr ',' ' ') ; do
    if id $J &> /dev/null ; then
      userdel -r $J &> /dev/null
      [ $DEBUG -eq 1 ] && echo "Delete user $J finished."
    else
      echo "$J does not exist yet."
    fi
  done
fi

while循环结构
while 命令; do 命令; done
在脚本中可以写成下列结构:
  while CONDITION  ; do
    COMMAND
  done

while循环进入循环的条件:CONDITION为真;
while循环退出循环的条件:CONDITION为假;

until循环结构
until 命令; do 命令; done
在脚本中可以写成下列结构:
  until CONDITION  ; do
    COMMAND
  done
until循环进入循环条件:CONDITION为假
until循环推出循环条件:CONDITION为真

注意:
  1.while CONDITION  相当于  until !CONDITION
  2.while和until循环结构中,没有变量自增或自减的变化方法;因此需要使用语句手动给出变量的变化方式;

写一个脚本,使用while或until循环,计算100以内整数的和;
#!/bin/bash
#
declare -i I=0
until [ $I -eq 100 ] ; do
  let I++
  let SUM+=$I
done

echo $SUM

#!/bin/bash
#
declare -i I=0
while [ $I -lt 100 ] ; do
  let I++
  let SUM+=$I
done

echo $SUM

循环控制语句:
  continue:
   continue [n]
    继续 for、while、或 until 循环。
    提前结束第N层当前循环,直接进入下一轮条件判断,如果条件判断结果仍然满足循环进入条件,则开启下一轮循环;
  break
    break [n]
    退出 for、while、或 until 循环
    提前结束第N层循环,且不再继续后续循环

while和until的两种特殊循环使用方法:
  1.无限循环方法
  while true ; do
    COMMAND
  done

until  false ; do
    COMMAND
  done

猜数字游戏:
#!/bin/bash
#
NUMBER=$[RANDOM%100+1]
while true ; do
  read -p "Input a number: " INPTNUM
  if [ $INPTNUM -gt $NUMBER ] ; then
    echo "Too big"
  elif [ $INPTNUM -lt $NUMBER ] ; then
    echo "Too small"
  else
    echo "Yes! you WIN. That's $NUMBER."
    break
  fi
done

#!/bin/bash
#
NUMBER=$[RANDOM%100+1]
until false ; do
  read -p "Input a number: " INPTNUM
  if [ $INPTNUM -gt $NUMBER ] ; then
    echo "Too big"
  elif [ $INPTNUM -lt $NUMBER ] ; then
    echo "Too small"
  else
    echo "Yes! you WIN. That's $NUMBER."
    break
  fi
done

注意:在此类循环结构中需要适当的添加continue或break,使无限循环可控;
 
 
  2.实现遍历功能的while和until循环结构
  while  read  LINES  ;  do
    COMMADN
  done <  /PATH/FORM/SOMEFILES

until  ! read  LINES  ;  do
    COMMADN
  done <  /PATH/FORM/SOMEFILES

注意:在做遍历循环时建议使用for;

select循环结构
 select NAME [in 词语 ... ;] do 命令; done
 select循环也是一种遍历列表的方式创建一个可视化菜单,每个列表中项都有一个数字编号与之对应,供用户选择使用,而用户只需要选择编号即可;
 select是一种默认无限循环结构;因此必须在循环体中卫select提供退出循环条件,通常可以使用break或exit命令实现;
 通常情况下,select循环会和case一起使用,以进行合理的取值判断;

在脚本中实现格式:
  select  VAR-NAME in  LIST ; do
    COMMAND
  done
  写一个脚本,显示以/bin/bash为默认shell的用户的ID信息;
#!/bin/bash
#
select I in $(awk -F : '/\/bin\/bash$/{print $1}' /etc/passwd) quit ; do
  case $I in
  quit)
    exit
    ;;
  *)
    echo "The UID of $I is $(id -u $I)"
    ;;
  esac
done

bash脚本编程--函数
对于bash来说,函数就是由命令和语句结构构成的能够实现特定功能集合;

为什么要用函数?
在bash脚本编写过程中,有可能会出现重复且不做任何改变的代码内容,如果这类内容完全依靠原始代码书写的话,不易于排错和优化;因此,可以选择将此类代码封装在函数中,在适当的场景中可以重复调用执行;

像此类被封装起来的代码块,通常称其为模块,也可以称为函数;

注意:1.想要使用函数,必须在使用前先定义;
          2.如果在某个bash脚本中包含了函数体,默认函数体中的各命令和语句不会被执行的;只有在调用函数名的时候,才会执行函数体中的命令和语句;
          3.通常需要重复执行的代码块或命令集,可以封装成函数;
          4.被调用的函数只能在调用函数的shell中被执行;

定义函数的方法:
  函数由两部分组成:
      函数名 + 函数体
      函数名:调用函数时所使用的字符串标识;在一个执行环境中,函数名不允许重复定义;
      函数体:能够实现特定独立功能的shell命令或结构化语句块;

定义的语法:
    语法一:
      function  function-name {
      func-body
      }
    语法二:
      func-name() {
      func-bady
      }
     注意:在语法二的格式中,func-name和()之间绝对不能有空格;

注意:函数可以在脚本中定义,也可以在当前shell中通过交互式环境定义;

函数的使用:
  函数在定义的时候,其函数体中包含的所有命令或结构化语句都不会被执行;只有在函数被调用时,才能执行其函数体中的各命令和语句;

调用方式:在命令行或脚本中,通过直接给出函数名的方式进行函数调用;

通常可以将常用的函数存放在专门用于保存函数的文件中;如果想调用这个文件中已经被定义保存的函数时;只需要在命令行或脚本中使用source命令(.命令)加载文件内容到当前shell中,然后再直接使用函数名调用函数即可;

函数的撤销:unset命令
  格式:# unset func-name
  注意:可以使用set命令查看当前已经定义生效的函数;

函数的返回值:
    两种返回值:
      函数的执行结果返回值:
        1.在函数体中所添加的命令有标准输出;
        2.在函数体中使用echo或printf命令强制输出返回信息;
      函数的执行状态返回值:
        1.默认情况下,其状态返回值为函数体中最后一条命令的状态返回值;
        2.自定义状态返回值(退出码):
          return命令
          return [n]
          从一个 shell 函数返回。            n: 0-255(1.2.127)为系统保留的状态码;尽量不用;
          注意:在函数被调用执行时,一旦遇到return命令,则不会再继续执行函数体中其他的后续命令,立刻结束次此函数的调用执行;

函数的生命周期:
        一般来讲,从函数被调用时开始,直到函数体中所有的命令和结构化语句全部执行完成,或者遇到return命令,则函数的调用结束;

函数的实参:
        对于bash的函数来说,没有形参,只有实参;
        bash函数的实参是使用$1,$2...位置变量提供数据的;
        可以使用$@,$*表示全部的参数列表;
        可以使用$#计算参数的个数;

注意:为函数提供参数时使用的位置变量,是调用函数名时在函数名后面的对应位置上的参数信息;与脚本位置参数不是一回事;

变量:函数被调用时必须在某特定的shell中被调用,因此,函数中可以继承并识别出环境变量和由调用函数shell定义的本地变量;

在函数中还可以定义一类局部变量:而局部变量仅在函数的生命周期内有效,因此在结束函数执行之前,应该撤销所有该函数定义的局部变量;

局部变量的定义方式:
          local VAR-NAME=值

变量的替换方式:
      前提:定义环境变量
#!/bin/bash
#
testvar() {
  local MYVAR=chinalink
  echo "Internal function: $MYVAR"
}
echo "Global variables: $MYVAR"
MYVAR=link
echo "External function, $MYVAR"
testvar

函数的递归调用:
        广义:在一个函数中调用另一个函数;
        狭义:在函数体中调用函数自身;
          直接调用:func1(){
                      func1
                    }
          间接调用:func2(){
                           func1
                           }
                           func1(){
                          func2
                           }
        
  函数直接递归调用示例1:
  计算某个数字的阶乘;
利用for循环:
#!/bin/bash
#
fact=1
if [ $1 -eq 0 ] ; then
  echo "0! is $fact"
elif [ $1 -eq 1 ] ; then
  echo "1! is $fact"
else
  for I in $(seq $1) ; do
    let fact=$[fact*$I]
  done
  echo "${1}! is $fact"
fi

利用函数递归调用:
#!/bin/bash
#
fact(){
  if [ $1 -eq 0 ] || [ $1 -eq 1 ] ; then
    echo 1
  else
    echo "$[$1*$(fact $[$1-1])]"
  fi
}

echo "${1}! is $(fact $1)"

示例2:
  斐波那契数列(黄金分割数列)

1 1 2 3 5 8 13 21 34 55 ...

N=N-1 + N-2

#!/bin/bash
#
fabonacci(){
  if [ $1 -eq 1 ] || [ $1 -eq 2 ] ; then
    echo -n "1 "
  else
    echo -n "$[$(fabonacci $[$1-1])+$(fabonacci $[$1-2])] "
  fi
}

for I in $(seq $1) ; do
  fabonacci $I
done
echo

示例三:
  汉诺塔

#!/bin/bash
#
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

转载于:https://blog.51cto.com/holmes975/2047443

朗科实习期间笔记心得(十)相关推荐

  1. 朗科实习期间心得笔记(五)

    bash特性 十二.bash变量 变量:一段有名称的连续的内存空间:这段内存空间的名称,称为变量名,在这段内存空间中存储数据,则称为变量值: 向内存空间(变量)中存储数据的过程,称为赋值操作:赋值的符 ...

  2. 朗科实习期间心得笔记(四)

    SHELL:   用户与操作系统之间完成交互式操作的一个接口程序,为用户提供简化了的操作. 上世纪70年代中期,Bell实验室,由bourne开发,bourne shell,简称sh:   Bill ...

  3. 朗科实习期间心得笔记(七)

    bash多命令执行方法:   1.命令替换     COMMAND1  $(COMMAND2)   2.管道     COMMAND1  |   COMMAND2  |  COMMAND3  .... ...

  4. 朗科实习期间心得笔记(八)

    其他的文本处理命令:     wc命令     cut命令    在文件的每一行中提取片断    注意:能够被cut命令修剪的文本文件或数据内容,一般是具有某种特定格式或结构的文本文件或数据内容:如: ...

  5. 朗科实习期间心得笔记(六)

    与用户账户和组账户相关的文件: /etc/passwd /etc/group /etc/shadow /etc/gshadow /etc/default/useradd /etc/login.defs ...

  6. JavaScript学习笔记(十)——学习心得与经验小结

    JavaScript学习笔记(十)--学习心得与经验小结 目前我先列好提纲,利用每晚和周末的闲暇时间,将逐步写完 ^_^ 转载于:https://www.cnblogs.com/mixer/archi ...

  7. SLAM学习笔记(十九)开源3D激光SLAM总结大全——Cartographer3D,LOAM,Lego-LOAM,LIO-SAM,LVI-SAM,Livox-LOAM的原理解析及区别

    本文为我在浙江省北大信研院-智能计算中心-情感智能机器人实验室-科技委员会所做的一个分享汇报,现在我把它搬运到博客中. 由于参与分享汇报的同事有许多是做其他方向的机器人工程师(包括硬件.控制等各方面并 ...

  8. 论文笔记(十六):Learning to Walk in Minutes Using Massively Parallel Deep Reinforcement Learning

    Learning to Walk in Minutes Using Massively Parallel Deep Reinforcement Learning 文章概括 摘要 1 介绍 2 大规模并 ...

  9. IT类实习/工作习惯心得

    转自 http://xiaozhao.renren.com/detail/experience/6685 实习 自2010年12月至2013年2月,我在导师公司实习,共计27个月.自2013年3月起, ...

最新文章

  1. 【舒工强烈推荐】命令添加Git远程仓库
  2. OO第一单元作业总结
  3. java招聘 试题_JAVA现场招聘考试题(一)
  4. 已触发了一个断点 vs_实现ABAP条件断点的三种方式
  5. sqlite3在Python2.7下对于中文路径的支持
  6. 保护计算机系统与数据有什么方法,电脑数据保护方法 看完保你不后悔
  7. Flutter ContrainedBox
  8. 在线3D大脑建模网站分享
  9. 笔记本连接外接显示器后耳机没有声音
  10. 无线路由器不能产生信号
  11. DIV display visibility
  12. Echarts 图表不能渲染问题整理
  13. 世界淡水资源占水资源的多少_世界上可用淡水资源到底是多少
  14. 04、Netty学习笔记—(黏包半包及协议设计解析)
  15. Plugin ‘org.springframework.boot:spring-boot-maven-plugin:‘ not found
  16. 【开关电源】电源仿真smplis
  17. 【GaussDB数据库简介】
  18. Java8 的 Stream简单教程
  19. BP神经网络+c代码
  20. SpringBoot——SpringBoot集成MyBatis

热门文章

  1. 分享一组程序员版的“鱿鱼游戏”趣图!
  2. 忘记密码手机号换了???
  3. 基于javaweb+jsp的校友信息管理系统
  4. java 可变参数--传数组(转)
  5. Linux系统创建桌面快捷方式,安装idea,配置idea环境
  6. android堆叠效果相册_android 图片叠加效果——两种方法
  7. NBA 2K11键盘按键操作介绍
  8. 导航定位向高精定位的演进与实践
  9. 有关于集成开发工具IntelliJ IDEA的安装
  10. 案例:鼠标精灵跟随效果