zoukankan      html  css  js  c++  java
  • Linux Shell脚本编程-语句控制

    过程式编程语言
    bash脚本编程面向过程的编程
      顺序执行:默认法则,按照顺序一条一条语句执行
      选择执行:分支,条件判断,符合条件的分支予以执行
      循环执行:将同一段代码反复执行有限次,所以循环必须有退出条件,否则将陷入死循环

    注意:
      顺序执行不需要特定的控制,只需按照语句依次执行即可;选择执行,则需要特定的控制语句(如:if、case)来判断执行;循环执行则需要特定的循环控制控制(如:for、while等)

    bash脚本编程之用户交互
      在bash脚本编程过程当中有时程序需要与用户之间进行交互(通过键盘输入数据),如提示用户输入一些参数等,此时,我们可以使用read命令来完成此功能
      read 通过提示信息输入一些信息存到变量中用于引用,达到与脚本交互的目的
      -p 指定提示信息
      -s 隐藏输入
      -n 指定输入的长度
      -t 用户长时间没有输入就退出(默认单位为秒)
     read -p "提示信息" varName

     注意:read从标准输入中读取值,给每个单词分配一个变量,所有剩余单词都被分配给最后一个变量
    演示:
    [root@centos7 ~]# read name
    tao
    [root@centos7 ~]# echo $name
    tao

    [root@centos7 ~]# read a b
    tom jerry
    [root@centos7 ~]# echo $a
    tom
    [root@centos7 ~]# echo $b
    jerry

    # 如果给定的参数少于变量个数,那么对应的参数为空的变量将为空
    [root@centos7 ~]# read a b c
    tom jerry
    [root@centos7 ~]# echo $a
    tom
    [root@centos7 ~]# echo $b
    jerry
    [root@centos7 ~]# echo $c

    # 如果给定的参数多于变量,那么多余的参数都将赋值给最后一个变量
    [root@centos7 ~]# read a b c
    tao tom jerry xiu
    [root@centos7 ~]# echo $a
    tao
    [root@centos7 ~]# echo $b
    tom
    [root@centos7 ~]# echo $c
    jerry xiu

    [root@centos7 ~]# echo -n "Enter a username: ";read name
    Enter a username: tao
    [root@centos7 ~]# echo $name
    tao

    [root@centos7 ~]# read -p "Enter a username: " name
    Enter a username: tom
    [root@centos7 ~]# echo $name
    tom

    [root@centos7 ~]# read -p "Enter a username: " name
    Enter a username: tom
    [root@centos7 ~]# [ -z "$name" ] && name="tao" # 如果变量为空时赋值为tao
    [root@centos7 ~]# echo $name
    tao

    示例脚本:
    [root@centos7 bin]# cat useradd2.sh
    #!/bin/bash
    #

    read -p "Enter a username: " name
    [[ -z "$name" ]] && echo "a username is needed" && exit 2


    if id $name &> /dev/null; then
      echo "$name exits."
    else
      read -p "Enter password for $name,[password]: " password
      [[ -z "$password" ]] && password="password"
      useradd $name
      echo "$password" | passwd --stdin $name &> /dev/null
      echo "Add user $name finished"
    fi

    给变量设置默认值:
      在这种交互式情况下如果用户没输入信息,给变量一个默认值的方法
      ${varName:-value}
      如果变量varName值不空,返回varName的值;如果为空返回值value;但是varName的值没有被改变为value
      varName=${varName:-value}
      如果变量varName值不空,变量varName的值不变;如果为空,变量varName的值为value

    bash中条件判断if语句
      单分支:
      if 条件; then
        分支1
      fi

     双分支:
      if 条件; then
        分支1
      else
        分支2
      fi

      多分支:
      if 条件; then
        分支1
      elif 条件2; then
        分支2
      elif 条件3; then
        分支3
        ...
      else
        分支n
      fi
        从上而下逐条件进行判断,第一次遇到为"真"条件时,执行其分支,而后结束整个if语句;即便多个条件可能同时满足,分支也只会执行其中一个,即首先测试为真的那个
      命令用作条件判断,就表示引用的是其状态结果(即执行成功与否),而非命令的输出返回结果,因此,不能使用命令替换符反引号``或$( )
    示例:
    1、通过参数传递一个用户名给脚本,此用户不存在时,则添加
    [root@centos7 bin]# cat useradd1.sh
    # 单分支语句
    #/bin/bash
    #

    if [ $# -lt 1 ]; then
      echo "At lest one username"
      exit 2
    fi

    if ! grep "^$1>" /etc/passwd &> /dev/null;then
      useradd $1
      echo $1 |passwd --stdin $1 &> /dev/null
      echo "Add user $1 finished"
    fi

    #双分支语句
    [ $# -lt 1 ] && echo "At lest add username" && exit 1
    if grep "^$1>" /etc/passwd &> /dev/null;then
      echo "user $1 exits"
    else
      useradd $1
      echo $1 |passwd --stdin $1 &> /dev/null
      echo "Add user $1 finished"
    fi

    # 方法二
    [[ $# -lt 1 ]] && echo "At lest one username" && exit 2
    if id $1 &> /dev/null; then
      echo "user $1 exits"
    else
      useradd $1
      echo $1 |passwd --stdin $1 &> /dev/null
      echo "Add user $1 finished"
    fi

    2、写一个脚本/root/bin/filetype.sh,判断用户输入文件路径,显示其文件类型(普通,目录,链接,其它文件类型)
    [root@centos7 bin]# cat filetype.sh
    #!/bin/bash
    #

    if [ $# -lt 1 ]; then
      echo "At least one path"
      exit 1
    fi

    if ! [ -e $1 ]; then
      echo "No such file"
      exit 2
    fi

    if [ -f $1 ]; then
      echo "Common file"
    elif [ -d $1 ]; then
      echo "Directory."
    elif [ -b $1 ]; then
      echo "Block special file."
    elif [ -c $1 ]; then
      echo "Character special file"
    elif [ -s $1 ]; then
      echo "Socket file."
    else
      echo "Unknow."
    fi

    3、根据提示让用户选择输入的信息:cpu,mem,disks,quit,正确就的选择就给出相应的信息,否则就提示重新选择正确的选项
    [root@centos7 bin]# cat menu.sh
    #!/bin/bash
    #

    cat << EOF
    cpu) display cpu information
    mem) diplay men information
    disks) display disks information
    quit) quit
    ======================================
    EOF

    read -p "Enter your option: " option

    while [ "$option" != "cpu" -a "$option" != "mem" -a "$option" != "disks" -a "$option" != "quit" ]; do
      echo "cpu mem disks quit"
      read -p "Enter your option again: " option
    done

    if [ "$option" == "cpu" ];then
      lscpu
    elif [ "$option" == "mem" ];then
      free -m
    elif [ "$option" == "disks" ];then
      fdisk -l /dev/[hs]d[a-z]
    else
      echo "quit"
      exit 0
    fi

    bash中条件判断case语句
      条件判断case语句(主要用于离散值的匹配)
      使用场景:case 语句在很多场景当中可以替换多分支的 if 语句,显示为更为简洁的格式,但其仅适用于:一个变量与多个取值之间作等值或者模式匹配时才可以用(即:拿一个变量来回跟多个可能的变量取值作比较才能使用或者说是,一个大的变量里面还有许多小的变量要选择才会用到),否则的话,只能用多分支的 if 语句
     语法:
      case $变量名 in
      "值1")
        如果是变量的值等于值1,则执行程序1
        ;;
      "值2")
        如果变量的值等于值2,则执行程序2
        ;;
      *)
        如果变量的值不是以上的值,则执行此程序
        ;;
      esac

      case 值 in
      模式1)
        分支1
        ;;
      模式2)
        分支2
        ;;

      *)
        默认分支
        ;;
      esac

      case支持glob风格的通配符:
      *  任意长度任意字符
      ?  任意单个字符
      []  指定范围内的任意单个字符[adc](也可以表示范围[1-10])
      a|b a或b

    示例:写一个脚本,完成如下任务
    A、显示一个如下菜单:
    cpu) show cpu information;
    mem) show memory information;
    disk) show disk information;
    quit) quit
    B、提示用户选择选项
    C、显示用户选择的内容
    #!/bin/bash
    #
    cat << EOF
    cpu) show cpu information;
    mem) show memory information;
    disk) show disk information;
    quit) quit
    ============================
    EOF

    read -p "Enter a option: " option
    while [ "$option" != 'cpu' -a "$option" != 'mem' -a "$option" != 'disk' -a "$option" != 'quit' ]; do
      read -p "Wrong option, Enter again: " option
    done

    case "$option" in
    cpu)
      lscpu
      ;;
    mem)
      cat /proc/meminfo
      ;;
    disk)
      fdisk -l
      ;;
    *)
      echo "Quit..."
      exit 0
      ;;
    esac

    2、写一个服务脚本,完成如下任务
    A、支持接受start,stop,restart,status四个参数之一;
    B、如果参数非此四值,则提示使用帮助后退出;
    C、start则创建lockfile,并启动;stop则删除lockfile,显示停止;restart,则先删除此文件,再创建此文件,而后显示启动完成;status,如果lockfile存在,则显示running,不存在,则显示 stopped

    [root@centos7 bin]# cat testservice.sh
    #!/bin/bash
    #
    #chkconfig: - 50 50
    #description: test service scipt
    #

    prong=$(basename $0)
    lockfile=/var/lock/subsys/$prong

    case $1 in
    start)
      if [ -f $lockfile ];then
        echo "$prong is running yet."
      else
        touch $lockfile
        [ $? -eq 0 ] && echo "start $prong finished."
      fi
      ;;
    stop)
      if [ -f $lockfile ];then
        rm -f $lockfile
        [ $? -eq 0 ] && echo "stop $prong finished."
      else
        echo "$prong is not running."
      fi
      ;;
    restart)
      if [ -f $lockfile ];then
        rm -f $lockfile
        echo "stop $prong finished."
        touch $lockfile
        echo "start $prong finished."
      else
        touch $lockfile
        echo "start $prong finished."
      fi
      ;;
    status)
      if [ -f $lockfile ];then
        echo "$prong is running"
      else
        echo "$prong is stopped"
      fi
      ;;
    *)
      echo "Usage: $prong {start|stop|restart|status}"
      exit 1
    esac

    #================================================================================
    # 复制到 /etc/init.d/ 目录下:
    [root@centos7 bin]# cp testservice /etc/init.d/
    [root@centos7 bin]# ls /etc/init.d/
    functions netconsole network README testservice.sh

    # 加入到 SysV 服务中去,使用 service 命令管控
    [root@centos7 bin]# chkconfig --add testservice
    [root@centos7 bin]# chkconfig --list testservice
    注意:该输出结果只显示SysV服务,并不包含原生systemd服务。SysV配置数据可能被原生 systemd 配置覆盖。
      查看systemd服务请执行:systemctl list-unit-files
      查看特定target启用的服务请执行:systemctl list-dependencies [target]
    testservice 0:关 1:关 2:关 3:关 4:关 5:关 6:关

    [root@centos7 bin]# ll /etc/init.d/testservice
    -rw-r--r-- 1 root root 798 3月 2 13:42 /etc/init.d/testservice

    # 给脚本一个执行权限
    [root@centos7 bin]# chmod +x /etc/init.d/testservice

    # 服务脚本测试如下
    [root@centos7 bin]# service testservice start
    start testservice finished.
    [root@centos7 bin]# service testservice start
    testservice is running yet.
    [root@centos7 bin]# service testservice restart
    stop testservice finished.
    start testservice finished.
    [root@centos7 bin]# service testservice stop
    stop testservice finished.
    [root@centos7 bin]# service testservice restart
    start testservice finished.
    [root@centos7 bin]# service testservice res
    Usage: testservice {start|stop|restart|status}
    [root@centos7 bin]# ls /var/lock/subsys/
    network testservice
    [root@centos7 bin]# service testservice stop
    stop testservice finished.

    # 注意:通过服务控制的脚本都会在启动完成后在/var/lock/subsys/下创建一个锁文件
    [root@centos7 bin]# service testservice stop
    stop testservice finished.
    [root@centos7 bin]# ls /var/lock/subsys/
    network
    [root@centos7 bin]# service testservice status
    testservice is stopped
    [root@centos7 bin]# service testservice start
    start testservice finished.
    [root@centos7 bin]# ls /var/lock/subsys/
    network testservice

    练习:
    1、写一个脚本/root/bin/createuser.sh,实现如下功能:使用一个用户名做为参数,如果指定参数的用户存在,就显示其存在,否则添加之;显示添加的用户的id号等信息

    2、写一个脚本/root/bin/yesorno.sh,提示用户输入yes或no,并判断用户输入的是yes还是no,或是其它信息

    3、写一个脚本/root/bin/checkint.sh,判断用户输入的参数是否为正整数

    bash中循环执行for语句
    for循环:通过使用一个变量去遍历给定列表中的每个元素。在每次变量赋值时执行一次循环体,直至赋值完成所有元素退出循环
      语法1
      for var_Name in 列表; do
        循环体(正常执行的执行命令)
        语句1
        语句2
        语句3
        ...
      done
      语法2
      for ((变量初始值;循环控制条件;变量变化));do
        循环体(正常执行的执行命令)
        语句1
        语句2
        语句3
        ...
      done
    例子:从1加到100
    #!/bin/bash
    s=0
    for ((i=1;i<=100;i=i+1));do
      s=$(($s+$i))
    done
    echo “The sum is:$s”

      列表的生成方法:
      直接给出列表
      生成数字列表
        大括号展开生成列表
        {start..end} 例子1到100 {1..100}
        通过seq命令生成列表,用的时候需要通过反引号``命令引用
        seq start       stop 例子1到100 `seq 1 100`
        seq start    step stop 例子1到100的奇数 `seq 1 2 100`
        seq 起始数字 步长 结束数字  
      返回列表的命令:$(COMMAND),如:$(ls)
      使用glob:如:*.sh
      变量引用:$@、$*

    示例:
    1、求100以内所有正整数之和
    #!/bin/bash
    #

    declare -i sum=0

    for i in {1..100};do
      echo "$sum is $sum, $i is $i"
      sum=$[$sum+$i]
    done

    echo $sum

    # 执行效果如下:
    [root@centos7 bin]# bash sum.sh
    $sum is 0, $i is 1
    $sum is 1, $i is 2
    $sum is 3, $i is 3
    $sum is 6, $i is 4
    $sum is 10, $i is 5
    $sum is 15, $i is 6
    $sum is 21, $i is 7
    $sum is 28, $i is 8
    $sum is 36, $i is 9
    $sum is 45, $i is 10
    ...
    5050

    # 100 以内所有偶数之和
    [root@centos7 bin]# sum=0;for i in `seq 0 2 100`;do sum=$[$sum+$i];done;echo $sum
    2550

    # 100 以内所有奇数之和
    [root@centos7 bin]# sum=0;for i in `seq 1 2 100`;do sum=$[$sum+$i];done;echo $sum
    2500

    # 求当前系统上所有用户的id之和
    [root@centos7 bin]# sum=0;for i in `cut -d: -f3 /etc/passwd`;do sum=$[$sum+$i];done ;echo $sum
    80311

    2、判断/var/log/目录下所有文件的文件类型
    [root@centos7 bin]# cat filetype1.sh
    #!/bin/bash
    #
    for filename in /var/log/*;do
      if [ -f $filename ]; then
        echo "$filename is Common file"
      elif [ -d $filename ]; then
        echo "$filename is Directory."
      elif [ -b $filename ]; then
        echo "$filename is Block special file."
      elif [ -c $filename ]; then
        echo "$filename is Character special file"
      elif [ -s $filename ]; then
        echo "$filename is Socket file."
      else
        echo "$filename is Unknow."
      fi
    done

      for循环的特殊格式
      for ((控制变量初始化;条件判断表达式;控制变量的修正表达式)); do
        循环体
      done

     控制变量初始化:仅在运行到循环代码段时执行一次
     控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后再做条件判断;

    示例1:求100以内所正整数之和;
    #!/bin/bash
    #
    declare -i sum=0
    for ((i=1;i<=100;i++)); do
      let sum+=$i
    done
    echo "Sum: $sum."

    示例2:打印九九乘法表;
    #!/bin/bash
    #
    for((j=1;j<=9;j++));do
      for((i=1;i<=j;i++))do
        echo -e -n "${i}X${j}=$[$i*$j] "
      done
      echo
    done

    示例3:写一个脚本,完成如下任务
    1、显示一个如下菜单:
    cpu) show cpu information;
    mem) show memory information;
    disk) show disk information;
    quit) quit
    2、提示用户选择选项;
    3、显示用户选择的内容;
    #!/bin/bash
    #
    cat << EOF
    cpu) show cpu information;
    mem) show memory information;
    disk) show disk information;
    quit) quit
    ============================
    EOF

    read -p "Enter a option: " option
    while [ "$option" != 'cpu' -a "$option" != 'mem' -a "$option" != 'disk' -a "$option" != 'quit' ]; do
      read -p "Wrong option, Enter again: " option
    done

    if [ "$option" == 'cpu' ]; then
      lscpu
    elif [ "$option" == 'mem' ]; then
      cat /proc/meminfo
    elif [ "$option" == 'disk' ]; then
      fdisk -l
    else
      echo "Quit"
      exit 0
    fi
    进一步地:用户选择,并显示完成后不退出脚本;而是提示用户继续输入选择;直到输入quit才会退出;

    bash中循环执行while语句
      while循环是不定循环,也称作条件循环。只要条件判断式成立,循环就会一直继续,直到条件判断式不成立,循环才会停止,这就和for的固定循环不太一样了;适用于循环次数未知的场景,要有退出条件;如何让while循环退出,在循环体中改变测试条件中用于控制循环变量的值;

    while语法:
     while CONDITION; do
       循环体
     done

     循环进入条件:CONDITION为true
     循环退出条件:CONDITION为false

    示例:求100以内所有正整数之和;
    #!/bin/bash
    declare -i sum=0
    declare -i i=1
    while [ $i -le 100 ]; do
      let sum+=$i
      let i++
    done
    echo "$i"
    echo "Summary: $sum."

    while循环的特殊用法(遍历文件的每一行)
    语法:
      while read VARIABLE; do
       循环体
     done < /PATH/FROM/SOMEFILE
    解释:依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量VARIABLE

    示例1s:找出ID号为偶数的用户,显示其用户名,ID,及默认的shell
    #!/bin/bash
    while read line;do
      userid=$(echo $line|cut -d: -f3)
      username=$(echo $line|cut -d: -f1)
      usershell=$(echo $line|cut -d: -f7)

    if [ $[$userid%2] -eq 0 ];then
      echo "$username,$userid,$usershell"
    fi
    done < /etc/passwd

    示例2:扫描/etc/passwd文件每一行,如发现GECOS字段为空,则填充用户名和单位电话为62985600,并提示该用户的GECOS信息修改成功
    #!/bin/bash
    #
    while read line;do
      string=$(echo $line| cut -d: -f5)
      username=$(echo $line| cut -d: -f1 )
      if [[ -z "$string" ]];then
        chfn -f "$username" $username &> /dev/null
        chfn -p "62985600" $username &> /dev/null
        echo "$username 用户信息添加完成"
      else
        echo "$username messages exits"
      fi
    done < /etc/passwd

    bash中循环执行until语句
      until循环和wehile循环相反,until循环时只要条件判断式不成立则进行循环,并执行行循环程序。一但循环条件成立,则终止循环。
      until语法:
       until CONDITION; do
          循环体
        done

      循环进入条件:CONDITION为false
      循环退出条件:CONDITION为true

    示例:求100以内所正整数之和
    #!/bin/bash
    #
    declare -i i=1
    declare -i sum=0

    until [ $i -gt 100 ]; do
      let sum+=$i
      let i++
    done
    echo "Sum: $sum"

    示例:打印九九乘法表
    #!/bin/bash
    #
    declare -i j=1
    declare -i i=1
    until [ $j -gt 9 ]; do
      until [ $i -gt $j ]; do
        echo -n -e "${i}X${j}=$[$i*$j] "
        let i++
      done
      echo
      let i=1
      let j++
    done

      创建无线循环
      while true; do
        循环体
      done

      until false; do
        循环体
     done

    循环控制语句(用于循环体中):
    continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断
    while CONDTIITON1; do
      CMD1
      ...
      if CONDITION2; then
        continue
      fi
      CMDn
      ...
    done

    break [N]:提前结束循环;
    while CONDTIITON1; do
      CMD1
      ...
      if CONDITION2; then
        break
      fi
      CMDn
      ...
    done

    示例1:求100以内所有偶数之和;要求循环遍历100以内的所正整数;
    #!/bin/bash
    #
    declare -i i=0
    declare -i sum=0
    until [ $i -gt 100 ]; do
      let i++
      if [ $[$i%2] -eq 1 ]; then
        continue
      fi
      let sum+=$i
    done
    echo "Even sum: $sum"

    示例2:每隔3秒钟到系统上获取已经登录的用户的信息;如果docker登录了,则记录于日志中,并退出;
    #!/bin/bash
    #
    read -p "Enter a user name: " username
    while true; do
      if who | grep "^$username" &> /dev/null; then
        break
      fi
      sleep 3
    done
    echo "$username logged on." >> /tmp/user.log

    第二种实现:
    #!/bin/bash
    #
    read -p "Enter a user name: " username
    until who | grep "^$username" &> /dev/null; do
      sleep 3
    done
    echo "$username logged on." >> /tmp/user.log

    for练习题:
    1、添加10个用户user1-user10,密码同用户名

    2、/etc/rc.d/rc3.d目录下分别有多个以K开头和以S开头的文件;分别读取每个文件,以K开头的文件输出为文件加stop,以S开头的文件输出为文件名加start

    3、写一个脚本,提示输入正整数n的值,计算1+2+3+…n的总和

    4、写一个脚本,提示请输入网络地址,如192.168.0.0,判断输入的网段中主机在线状态
    #!/bin/bash
    #authoe:tao
    #describtion:给定一个网络地址,并探测此网络中主机的在线状态,并统计出在线主机和离线主机的个数

    read -p "请输入您的IP地址: " IP

    declare -i i=0
    declare -i j=0

    address=$(echo $IP |egrep "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])")
    arg3=$(echo $IP |cut -d. -f1-3).

    if [[ -z "$IP" ]];then
      echo "At least one IPv4." && exit 1
    elif [[ "$IP" == "$address" ]];then
      for arg4 in $(seq 100 110);do
        if ping -c1 -W1 $arg3$arg4 &> /dev/null ;then
          echo -e "$arg3$arg4 up."
          let i++
        else
          echo -e "$arg3$arg4 down."
          let j++
        fi
      done
    else
      echo "您输入的格式不正确,请重新输入!" && exit 2
    fi

    echo "在线主机的个数为:$i"
    echo "不在线主机的个数为:$j"

    #=================================================================
    # 执行结果如下:
    [root@centos7 bin]# bash ping.sh
    请输入您的IP地址: 192.168.1.1
    192.168.1.100 up.
    192.168.1.101 up.
    192.168.1.102 up.
    192.168.1.103 down.
    192.168.1.104 down.
    192.168.1.105 down.
    192.168.1.106 up.
    192.168.1.107 down.
    192.168.1.108 down.
    192.168.1.109 down.
    192.168.1.110 down.
    在线主机的个数为:4
    不在线主机的个数为:7

    while练习题
    1、通过ping命令探测172.16.250.1-254范围内的所有主机的在线状态,统计在线主机和离线主机各多少。

    2、打印九九乘法表

    3、利用变量RANDOM生成10个随机数字,输出这个10数字,并显示其中的最大者和最小者

    4、打印国际象棋棋盘

    until练习题
    1、每隔3秒钟到系统上获取已经登录的用户的信息;如果发现用户hacker登录,则将登录时间和主机记录于日志/var/log/login.log中,并提示该用户退出系统

    2、随机生成10以内的数字,实现猜字游戏,提示比较大或小,相等则退出

     

  • 相关阅读:
    Java学习笔记21---内部类之对成员内部类的补充说明(二)(修正)
    Java学习笔记20---内部类之对成员内部类的补充说明(一)
    Java学习笔记19---内部类之简介成员内部类、局部内部类及匿名内部类
    Java学习笔记18---final关键字修饰变量、方法及类
    Java学习笔记17---成员方法的重载与重写
    Java学习笔记16---抽象类与接口的浅显理解
    Java学习笔记15---instanceof与向下转型
    把大端、小端与堆、栈的生长方向联系起来记忆
    2020综合实践—第7次实践作业 03组
    2020综合实践 第6次实践作业 03组
  • 原文地址:https://www.cnblogs.com/Link-Luck/p/9854971.html
Copyright © 2011-2022 走看看