朗科学习期间心得笔记(九)

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

过程式编程语言的结构:
    顺序执行结构:从上到下,从左向右的执行所有语句(命令);
    选择执行结构:当条件满足或不满足时,才会执行对应的语句(命令);
    循环执行结构:重复执行某段语句(命令);

bash脚本编程语言中,也具备上述结构;其默认为顺序执行结构;
  
   
   选择执行结构:根据给定条件的逻辑判断结果,或根据某个可选取的取值范围,进而选择某个分支结构中的命令语句予以执行的方式;
     if:
       选择执行结构的标准,根据条件的逻辑判断结果选择执行的语句内容;
     case:
       选择执行结构的标准,根据符合某特定范围的取值标准选择执行的语句内容;
   
   循环执行结构:对于特定语句内容,重复执行0次,1次或多次;
     for:以遍历列表的方式进行循环;
     while:根据给定条件的逻辑判断结果;逻辑判断结果为真才循环,否则停止循环;
     until:根据给定条件的逻辑判断结果;逻辑判断结果为假才循环,否则停止循环;
     select:死循环,即没有默认退出条件的循环;利用循环提供一个可选择的列表;例如: $RANDOM

bash脚本的执行结构---if选择执行结构
  if 命令; then 命令; [ elif 命令; then 命令; ]... [ else 命令; ] fi

if语句的单分支结构
    if 命令; then 命令; fi
    注意:是否会执行then后的命令,取决于if后命令的状态返回值,如果其返回值为真则执行then后的命令,否则不执行then后的命令;

建议在脚本中的书写格式:
      if  CONDITION(条件)  ;then  
        STATEMENT
        ...
        fi

if语句的双分支结构
    if 命令; then 命令;  [ else 命令; ] fi

注意:如果其返回值为真则执行then后的命令,返回值为假则执行else后的命令;
    if  CONDITION(条件)  ;then  
        STATEMENT
        ...
        else
        ...
        fi

if语句的多分支结构
    if 命令; then 命令; [ elif 命令; then 命令; ]... [ else 命令; ] fi

注意:是否会执行then后的命令,取决于if后命令的状态返回值或elif后命令的状态返回值,如果if为真则执行then后命令,如果为假则继续判断第一个elif后命令的返回值,第一个elif返回值为真则执行第一个elif语句中then后命令,否则判断第二个elif后命令的返回值.....如果所有的if,elif后的命令返回值都为假,则执行else后ude命令;

if  CONDITION(条件)  ;then  
           STATEMENT
           ...
        elif CONDITION2  ;  then
           STATEMENT
           ...
        elif CONDITION2  ;  then
           STATEMENT
           ...
        ...
        else
        ...
        fi  
      注意:if的多分支结构,使用场景不多,而且有些时候,可以使用嵌套的单分支或双分支if结构代替多分支结构;

嵌套if结构:
        if  condition1  ; then
          if  condition2  ; then
            if  condition3  ; then
              statement
              ...
            else
              statement
              ...
            fi
          else
            statement
            ...
          fi
        else
          statement
          ...
        fi

示例:
    1.写一个脚本,判断某个用户的默认登录shell是否为/bin/bash;
#!/bin/bash
#
USERNAME=$(cut -d: -f1 /etc/shadow | sort -R | head -1)
USERSHELL=$(egrep "^$USERNAME\>" /etc/passwd | cut -d: -f7)
if [ "$USERSHELL" == "/bin/bash" ] ; then
  echo "${USERNAME}'s login shell is /bin/bash."
fi

unset USERNAME USERSHELL

2.写一个脚本,判断某个用户的默认登录shell是否为/bin/bash,如果不是,显示其登录shell
#!/bin/bash
#
USERNAME=$(cut -d: -f1 /etc/shadow | sort -R | head -1)
USERSHELL=$(egrep "^$USERNAME\>" /etc/passwd | cut -d: -f7)
if [ "$USERSHELL" == "/bin/bash" ] ; then
  echo "${USERNAME}'s login shell is /bin/bash."
else
  echo "${USERNAME}'s login shell is ${USERSHELL}"
fi

unset USERNAME USERSHELL

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

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

read命令:
    Read a line from the standard input and split it into fields.
    read - read [-a array] [-p prompt] [-t timeout] [name ...]
      -a array:定义索引数组;
      -p prompt:给用户输出提示信息;
      -t timeout:用户输入的超时时间;
      name:变量或数组的名称;如果省略此内容,bash会将read读到的信息直接保存到内置的名为REPLY变量中;

注意:
      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
if [[ $1 =~ ^[[:digit:]]+$ ]] ; then
  echo "$1 is a pure digit."
else
  echo "$1 is not a digit."
fi

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

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

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

for循环:
    1.遍历列表的循环:
      Execute commands for each member in a list.
      for - for NAME [in WORDS ... ] ; do COMMANDS; done

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

注意:
        VAR_NAME:任意指定的变量名称,变量的值是从LIST中遍历获取的各个元素;
        LIST:for循环需要遍历的列表;可以通过以下方式生成列表:
          1.直接给出列表;
          2.纯整数列表:
            1) 花括号展开:
              {FIRSTNUMM..LASTNUM}
              {FIRST,SECOND,THIRD,....,LAST}
            2) seq命令
              seq [OPTION]... LAST
              seq [OPTION]... FIRST LAST
              seq [OPTION]... FIRST INCREMENT LAST
          3.花括号展开:
            {FIRST..LAST}
          4.命令的执行结果:
            ls /etc
            grep /PATH/TO/SOMEFILE
          5.GLOBBING
          6.某些特殊变量的值:
            $*, [email protected]
        循环体:
          一般来说,循环体中应该包括能够用到VAR_NAME变量的值的命令或命令的组合;如果循环体中的命令并没有用到VAR_NAME变量的值的话,列表的元素个数就是此次for循环的次数;

写一个脚本,计算1到100的数字之和;
#!/bin/bash
#
declare -i SUM=0
for I in {1..100} ; do
  SUM=$[SUM+I]
done
echo "The summary is: $SUM"

写一个脚本,能够通过-a或-d选项添加或删除一个或多个用户账户;
#!/bin/bash
#
if [ $# -lt 2 ] ; then
  echo "Make sure provide more than TWO arguments."
  exit 5
fi

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

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

计算指定数字范围内自然数的和:
#!/bin/bash
#
declare -i SUM=0
read -p "Please input TWO integer: " INT1 INT2
if [[ $INT1 =~ [^[:digit:]] ]] ; then
  echo "$INT1 must be an integer."
  exit 5
fi

if [[ $INT2 =~ [^[:digit:]] ]] ; then
  echo "$INT2 must be an integer."
  exit 5
fi

if [ $INT1 -gt $INT2 ] ; then
  for I in $(seq $INT2 $INT1) ; do
# SUM=$[SUM+I]
    let SUM+=$I
  done
  echo "The summary is: $SUM"
else
  for I in $(seq $INT1 $INT2) ; do
# SUM=$[SUM+I]
    let SUM+=$I
  done
  echo "The summary is: $SUM"
fi

写一个脚本,打印有"*"组成的倒置的等腰三角形;
*********   1行,0个空白字符,9个*
 *******    2行,1个空白字符,7个*
  *****     3行,2个空白字符,5个*
   ***      4行,3个空白字符,3个*
    *       5行,4个空白字符,1个*

N行,N-1个空白字符,2*(总行数-当前行号)+1 个*
#!/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 $[I-1]) ; do
    echo -n " "
  done
  for K in $(seq $[2*(LINENUM-I)+1]) ; do
    echo -n "*"
  done
  echo
done

打印九九乘法表
第一行:1个
第二行:2个
...
第九行:9个

#!/bin/bash
#
for I in {1..9} ; do
  for J in $(seq $I) ; do
    echo -ne "$I×$J=$[I*J]\t"
  done
  echo
done

#!/bin/bash
#
for (( I=1 ; I<=9 ; I++ )) ; do
  for (( J=1 ; J<=I ; J++ )) ; do
    echo -ne "$J×$I=$[I*J]\t"
  done
  echo
done

以上两个例子,均使用for循环的嵌套;往往需要两层的循环嵌套才能打印出平面效果;外层的for循环,负责控制行数输出;内层的for循环,负责控制每一行中各个列的输出;

2.通过控制变量实现for循环:
      for (( exp1; exp2; exp3 )); do COMMANDS; done
      可以在脚本中写成如下格式:
        for (( exp1; exp2; exp3 )); do
          COMMANDS
        done

exp1:表达式1,为指定的变量赋初始值;
      exp2:表达式2,此次循环的退出条件;
      exp3:表达式3,指定的变量的值的变化规律;

计算从1到100的自然数的和;
#!/bin/bash
#
for (( I=1 ; I<=100 ; I++ )) ; do
  let SUM+=$I
done
echo "The summary is: $SUM"

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

时间: 2024-08-30 02:09:44

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

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

与用户账户和组账户相关的文件:/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称为字段列表,地址定界,其书写方法:      

APUE 学习笔记(九) 高级I/O

1. 非阻塞I/O 低速系统调用时可能会使进程永远阻塞的一类系统调用,包括以下调用: (1)某些文件类型你(网络socket套接字.终端设备.管道)暂无可使用数据,则读操作可能会使调用者永远阻塞 (2)如果数据不能立即被(1)中文件类型接受,则写操作会使调用者永远阻塞 (3)某些进程间通信函数 非阻塞I/O使我们可以调用open.read.write这样的I/O操作,并使这些操作不会永远阻塞,如果这种操作不能完成,则调用立即出错返回 对于一个给定的文件有两种方法对其指定非阻塞I/O: (1)调用

python学习笔记九——文件与目录

1.python进行文件读写的函数是open或file类 mode:r  只读 r+   读写 w  写入,先删除原文件,再重新写入,如果文件没有则创建 w+  读写,先删除原文件,再重新写入,如果文件没有则创建(可写入和输出) a  写入,在文件末尾追加新的内容,文件不存在则创建 a+  读写,在文件末尾追加新的内容,文件不存在则创建 b  打开二进制文件,可与r,w,a,+结合使用 U  支持所有的换行符号,"\r","\n","\r\n"

angular学习笔记(九)-css类和样式3

再来看一个选择li列表的例子: 点击li中的任意项,被点击的li高亮显示: <!DOCTYPE html> <html ng-app> <head> <title>6.3css类和样式</title> <meta charset="utf-8"> <script src="../angular.js"></script> <script src="scri

angular学习笔记(九)-css类和样式2

在上一个例子中,元素的类名使用拼接的方法,这样,类名中就不得不带有true或false,并且不易维护,所以,angular使用ng-class属性来控制元素的类名: 我们来看一个小例子,点击error按钮,顶部提示错误框,点击warning按钮,顶部提示警告框. 错误框的类名是.err,警告框的类名是.warn: <!DOCTYPE html> <html ng-app> <head> <title>6.2css类和样式</title> <

Linux System Programming 学习笔记(九) 内存管理

1. 进程地址空间 Linux中,进程并不是直接操作物理内存地址,而是每个进程关联一个虚拟地址空间 内存页是memory management unit (MMU) 可以管理的最小地址单元 机器的体系结构决定了内存页大小,32位系统通常是 4KB, 64位系统通常是 8KB 内存页分为 valid or invalid: A valid page is associated with an actual page of data,例如RAM或者磁盘上的文件 An invalid page is

虚拟机VMWare学习笔记九 - 物理机上的文件挂载到虚拟机上

物理机上的文件夹或盘符直接挂载到虚拟机上使用. VM -- Settings Options -- Shared Folders -- 勾选Always enabled , 勾选Map as a network drive in Windows guests 在点击下面的添加来添加共享的文件夹 选择路径 可以看到虚拟机中的共享文件夹已经出现在Windows 中了 虚拟机VMWare学习笔记九 - 物理机上的文件挂载到虚拟机上

我的MYSQL学习心得(九)

我的MYSQL学习心得(九) 我的MYSQL学习心得(一) 我的MYSQL学习心得(二) 我的MYSQL学习心得(三) 我的MYSQL学习心得(四) 我的MYSQL学习心得(五) 我的MYSQL学习心得(六) 我的MYSQL学习心得(七) 我的MYSQL学习心得(八) 这一篇<我的MYSQL学习心得(九)>将会讲解MYSQL的索引 索引是在存储引擎中实现的,因此每种存储引擎的索引都不一定完全相同,并且每种存储引擎也不一定支持所有索引类型. 根据存储引擎定义每个表的最大索引数和最大索引长度.所有