朗科实习期间笔记心得(十)

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...位置变量提供数据的;
        可以使用[email protected],$*表示全部的参数列表;
        可以使用$#计算参数的个数;

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

变量:函数被调用时必须在某特定的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

时间: 2024-10-02 20:02:21

朗科实习期间笔记心得(十)的相关文章

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

与用户账户和组账户相关的文件:/etc/passwd/etc/group/etc/shadow/etc/gshadow/etc/default/useradd/etc/login.defs/etc/skel(directory) /etc/passwd:用户名解析库root:x:0:0:root:/root:/bin/bash   1  2 3  4   5         6     7    1字段:用户账户登陆名称2字段:使用 X 表示密码占位符3字段:用户账户的UID4字段:用户账户的G

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

其他的文本处理命令:    wc命令    cut命令   在文件的每一行中提取片断   注意:能够被cut命令修剪的文本文件或数据内容,一般是具有某种特定格式或结构的文本文件或数据内容:如:/etc/passwd   cut [OPTION]... [FILE]...   常用选项   -d:指定在实施修剪操作时所使用的字段分隔符号,默认是TAB(空白字符):   -f:根据我们指定的字段分隔符号来指定要保留的字段编号的列表:     LIST称为字段列表,地址定界,其书写方法:      

48. 蛤蟆的数据结构笔记之四十八的有向无环图的应用关键路径

48. 蛤蟆的数据结构笔记之四十八的有向无环图的应用关键路径 本篇名言:"富贵不淫贫贱乐 ,男儿到此是豪雄.-- 程颢" 这次来看下有向无环图的另一个应用关键路径. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47135061 1.  关键路径 与AOV-网相对应的是AOE-网(Activity On Edge)即边表示活动的网.AOE-网是一个带权的有向无环图,其中,顶点表示事件(Event),弧表示活动,权表

42. 蛤蟆的数据结构笔记之四十二图的遍历之广度优先

42. 蛤蟆的数据结构笔记之四十二图的遍历之广度优先 本篇名言:"生活真象这杯浓酒 ,不经三番五次的提炼呵 , 就不会这样一来可口 ! -- 郭小川" 继续看下广度优先的遍历,上篇我们看了深度遍历是每次一个节点的链表是走到底的. 欢迎转载,转载请标明出处:http://write.blog.csdn.net/postedit/47029275 1.  原理 首先,从图的某个顶点v0出发,访问了v0之后,依次访问与v0相邻的未被访问的顶点,然后分别从这些顶点出发,广度优先遍历,直至所有的

49. 蛤蟆的数据结构笔记之四十九图的连通性问题

49. 蛤蟆的数据结构笔记之四十九图的连通性问题 本篇名言:"我们不得不饮食.睡眠.游惰.恋爱,也就是说,我们不得不接触生活中最甜蜜的事情:不过我们必须不屈服于这些事物 .....--约里奥?居里"     此篇就作为数据结构入门笔记的最后一篇吧. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47135259 设图G=(V,E)是一个无向图,G的一个连通分支是一个最大的连通子图,即一个连通分支是不包含在任何更大的

46. 蛤蟆的数据结构笔记之四十六普里姆算法

46. 蛤蟆的数据结构笔记之四十六普里姆算法 本篇名言:"手莫伸 ,伸手必被捉.党与人民在监督 ,万目睽睽难逃脱.汝言惧捉手不伸 ,他道不伸能自觉 , 其实想伸不敢伸 ,人民咫尺手自缩.-- 陈毅" 连通图的生成树是一个极小的连通子图,它含有图中全部的顶点,但只有足以构成一棵树的n-1条边.所谓的最小成本,就是n个顶点,用n-1条边把一个连通图连接起来,并且使得权值的和最小.构造连通网的最小代价生成树,即最小生成树(Minimum Cost Spanning Tree). 找连通图的最

44. 蛤蟆的数据结构笔记之四十四弗洛伊德Floyd算法

44. 蛤蟆的数据结构笔记之四十四弗洛伊德Floyd算法 本篇名言:"希望是厄运的忠实的姐妹. --普希金" 我们继续来看下数据结构图中的一个算法,这个算法来自图灵奖得主. 1.  Floyd算法介绍 Floyd算法又称为插点法,是一种用于寻找给定的加权图中多源点之间最短路径的算法.该算法名称以创始人之一.1978年图灵奖获得者.斯坦福大学计算机科学系教授罗伯特·弗洛伊德命名.注意这个可不是心理学的那个弗洛伊德. 是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径

《Programming in Lua 3》读书笔记(二十二)

日期:2014.8.6 PartⅣ The C API 26 Extending Your Application 使用Lua很重要的一点是用来做配置语言.配合主语言做一些功能的配置. 26.1 The Basics 有的时候程序需要配置一些功能信息,很多时候可能有许多别的方法比用lua做配置要更简单:如使用环境变量或者读取文件,读取文件涉及到文件的解析.如果使用Lua进行配置的话,相当于用lua文件替代了要读取的如csv.txt文件等. 使用Lua进行配置的时候,就需要使用Lua API去控制

一个怂女婿的成长笔记【十五】

2014-08-16 大部分人不是没有选择生活方式的权利,而是没有勇气去做出改变罢了. 我们经常在抱怨现在的生活不是自己想要的,但是当我们自问什么生活才是自己想要的时候,我们又偏偏答不出来,或者觉得太虚幻.所以,我们经常抱怨上天,抱怨公司,抱怨体制的时候,有没有想过,不是我们改变不了现在的生活,而是我们没有勇气去改变,而找了一些借口罢了. 记得一年前,我看过一篇<降级论>的文章,作者之前也是一名程序员,后来选择了其他行业,过上了自己想要的生活.但是我这里的意思不是觉得程序员的职业不好,或者没前