20201220蔡笃俊《信息安全系统设计与实现》第十章学习笔记

一、任务内容

  • 自学教材第10章,提交学习笔记(10分)

  • 大家学习过Python,C,Java等语言,总结一下一门程序设计语言有哪些必备的要素和技能?这些要素和技能在shell脚本中是如果呈现出来的?

  • 知识点归纳以及自己最有收获的内容 (3分)

  • 问题与解决思路(2分)

  • 实践内容与截图,代码链接(3分)

  • ...(知识的结构化,知识的完整性等,提交markdown文档,使用openeuler系统等)(2分)

二、知识点归纳以及自己最有收获的内容

1.知识点归纳

在这之前,我们要先了解一下,什么是shell编程?

高大上的解释,往往让人摸不住头脑。一句话概括就是:shell编程就是对一堆Linux命令的逻辑化处理。sh脚本是一个包含sh语句的文本文件,命令解释程序sh要执行该语句;C程序与其在根本上是不同的。首先,sh是一个解释程序,逐行读取sh脚本文件并直接执行这些行,相反,C程序必须先编译链接到一个二进制可执行文件,然后通过主sh的子进程运行二进制可执行文件;其次,在C程序中,每个变量必须有个类型,相反,在sh脚本中,每个变量都是字符串;最后,每个C程序必须有一个main()函数,每个函数必须定义一个返回值类型和参数,相反,sh脚本不需要main函数。

我们可以从最基本的sh脚本开始:

#!/bin/bash    # 这句话表示用linux指定去解析文本内容
#第一个shell小程序
echo hello world!

  • 第一行表示我们选择使用bash shell。shell中#符号表示注释。shell的第一行比较特殊,一般都会以#!开始来指定使用的shell类型。在linux中,除了bash shell以外,还有很多版本的shell, 例如zsh、dash等等…不过bash shell还是我们使用最多的。

  • 第二行以#符号开始,表示本行是注释,运行的时候是不会运行本行的。

  • 第三行中的echo是linux中的输出命令,该行的意思很明显的就是输出hello world!

  • chmod +x hello.sh 的意思是赋予hello.sh的可执行权限

  • 在linux中,后缀名几乎是可以任意的或者没有后缀名,一般将shell保存为xxx.shell是为了看起来更直观

了解了最基本的sh编程,让我们开始深入了解sh吧!

1. 命令行参数

  • $#=命令行参数\(1到\)n的数量;
  • $*=所有命令行参数,包括$0;
  • 此外,sh还有与命令执行相关的以下内置变量:
  • $S=执行sh进程PID;
  • $?=最后一个命令执行的退出状态(如果成功,则为0,否则为非0)

2. sh变量

在sh中,什么是变量?

变量是计算机内存的单元,其中存放的值可以改变。当Shell脚本需要保存一些信息时,如一个文件名或是一个数字,就把它存放在一个变量中。每个变量有一个名字,所以很容易引用它。使用变量可以保存有用信息,使系统获知用户相关设置,变量也可以用户保存暂时信息。
shell编程中,我们可以把变量分成两种,一种是我们自己定义的变量(自定义变量),可以通过set命令查看系统变量;第二种是Linux已定义的环境变量(如 PATH,HOME,TERM等等……这类变量我们可以直接使用)需要记住的是:变量设置要遵循变量设置规则,定义变量不用[$]符号,使用变量加符号即可。

变量设置规则

* 变量名称可以由字母、数字和下划线组成,但不能以数字开头。
* 变量的默认类型都是字符串型
* 变量用等号连接值,等号左右两侧不能有空格。
* 变量的值如果有空格,需要使用单引号或者双引号苦括起来。
* 不能使用标点符号

3. sh中的引号

sh有许多特殊字符,如S、/、*、>、<等。要想把它们用作普通字符,可使用\或单引号来引用它们。通常,‘\’用于引用单个字符。单引号用于引用长字符串。单引号内没有替换。双引号用于保留双引号字符串中的空格,但在双引号内会发生替换。

4. sh语句

sh语句包括所有Unix/Linux命令,以及可能的I/O重定向。此外,sh编程语言还支持控制sh程序执行的测试条件、循环、case等语句。此外,sh编程语言还支持控制sh程序执行的测试条件、循环、case等语句。

5. sh命令

  • 内置命令

    • .file:读取并执行文件。
    • break [n]:从最近的第n个嵌套循环中退出。
    • cd [dirname]: 更换目录。
    • continue[n]:重启最近的第n个嵌套循环。
    • eval [arg...]:计算一次参数并让sh执行生成的命令。
    • exec [arg...]:通过这个sh执行命令,sh将会退出。
    • exit [n]:使sh退出,退出状态为n。
    • export [var…]:将变量导出到随后执行的命令.
    • read [var...]:从stdin 中读取一行并为变量赋值。
    • set [arg...]:在执行环境中设置变量。
    • shift:将位置参数$2 $3...重命名为 $1 $2...。
    • trap [arg] [n]:接收到信号n后执行参数。
    • umask [ddd]:将掩码设置为八进制数 ddd 的。
    • wait pid]: 等待进程 pid,如果没有给出pid,则等待所有活动子进程。
  • Linux命令

    • echo命令:将参数字符串作为行回显到stdout。
    • expr命令:间接更改sh变量的值。
    • 管道命令:作为过滤器。
    • 实用命令:
      • axk:数据处理程序。
      • cmp:比较两个文件。
      • comm:选择两个排序文件共有的行。
      • grep:匹配一系列文件的模式。
      • diff:找出两个文件的差异。
      • join:通过使用相同的键来连接记录以比较两个文件。
      • sed:流或行编辑命令。
      • sort:排序或合并文件。
      • tail:打印某个文件的最后口行。
      • tr:一对一宇符翻译。
      • uniq:从文件中删除连续重复行。

6. sh命令替换

在sh中,\(A会被替换成A值。同样,当sh遇到‘cmd’或\)(cmd)时,它会先执行cmd,然后用执行的结果字符替换$(cmd)。

7. sh控制语句

  • if语句

    • if条件语句

      if [ 条件判断 ];then
      程序
      fi
      

      或者

      if [ 条件判断 ]
        then
          程序
      fi
      

      实践:

      #!/bin/bash
      
      #统计根分区使用率
      rate=$(df -h | grep /dev/vda1 | awk '{print $5}' | cut -d "%" -f 1)
      
      if [ $rate -ge 20 ]
        then
      echo "error 10"
      fi
      
    • if else条件语句

      if [ 条件判断 ]
        then
          条件成立时,执行此程序
        else
           条件不成立时,执行的另外一个程序
      fi
      

      实践:

      #!/bin/bash
      
      #备份mysql数据库
      
      #同步系统时间
      ntpdate asia.pool.ntp.org &>/dev/null
      #把当前系统时间按照“年月日”格式赋予变量date
      date=$( date+%y%m%d )
      #统计mysql的数据库大小,并把大小赋予size变量
      size=$( du -sh /var/lib/mysql )
      
      if [ -d /tmp/dbback ]
        then
          echo "Date: $date!" > /tmp/dbback/dbinfo.txt
          echo "Date size: $size" >> /tmp/dbback/dbinfo.txt
          cd /tmp/dbback
          tar -zcf mysql-lib-$date.tar.gz /var/lib/mysql dbinfo.txt &>/dev/null
          rm -rf /tmp/dbback/dbinfo.txt
       else
          mkdir /tmp/dbback
          echo "Date: $date!" > /tmp/dbback/dbinfo.txt
          echo "Date size: $size" >> /tmp/dbback/dbinfo.txt
          cd /tmp/dbback
          tar -zcf mysql-lib-$date.tar.gz /var/lib/mysql dbinfo.txt &>/dev/null
          rm -rf /tmp/dbback/dbinfo.txt 
      fi
      
    • 多分支if条件语句

       if [ 条件判断式1 ]
        then
          当条件判断式1成立时,执行程序1
       elif [ 条件判断式2 ]
          then
        当条件判断式2成立时,执行程序2
      ...省略更多条件
      else 
      当所有条件都不成立时,最后执行此程序
      fi
      

      实践:

      #!/bin/bash
      
      #接收键盘输入,并赋予变量file
      read -p "Please input a filename: " file
      
      #判断file变量是否为空
      if [ -z "$file" ]
        then
          echo "error,请输入文件名"
          exit 1
      #判断file的值是否存在
      elif [ ! -e "$file" ]
        then
          echo " 你的文件不存在"
          exit 2
      #判断file的值是否为普通文件
      elif [ -f "$file" ]
        then
          echo "文件是普通文件"
      #判断file的值是否为目录文件
      elif [ -d "$file" ]
        then
        echo "文件是目录文件"
      else
        echo "文件是其他类型的"  
      fi
      
  • case语句

     case $变量名 in
      "值1")
          如果变量的值等值1,则执行程序1
          ;;
       "值2")
          如果变量的值等值2,则执行程序2
          ;;    
        ……省略其他分支
        *)
           如果变量的值都不是以上的值,则执行程序
           ;;
    esac
    

    实践:

    #!/bin/bash
    #测试case语句
    
    echo "如果想去上班,请输入“1”"
    echo "如果不想上班,请输入“2”"
    echo "如果想居家办公,请输入“3”"
    
    read -t 30 -p "请输入你的选择:" choose
    
    case "$choose" in
            "1")
                    echo "想去上班!"
                    ;;
            "2")
                    echo "不想去上班!"
                    ;;
            "3")
                    echo "居家办公!"
                    ;;
            *)
                    echo "只能输入1或者2或者3"
                    ;;
    esac
    
  • for循环

语法一

for 变量 in 值1 值2 值3...
  do
    程序
  done

实践:

#!/bin/bash
#打印1??6的循环
for i in 1 2 3 4 5 6
        do
                echo $i
        done

语法二:

for (( 初始值;循环控制条件;变量变化 ))
  do
    程序
  done

实践:

#!/bin/bash
#使用for循环计算1-100的和
s=0
for (( i=1;i<=100;i=i+1 ))
        do
                s=$(( $s+$i ))
        done
                echo "$s"

#!/bin/bash
#批量添加指定数量的用户

read -t 30 -p "Please input user name:" name
read -t 30 -p "Please input the mumber of users:" num
read -t 30 -p "Please input the password of users:" pass

if [ ! -z "$name" -a ! -z "$num" -a ! -z "$pass" ]
        then
        y=$(echo $num | sed 's/[0-9]*$'//g)
                if [ -z "$y" ]
                then
                for (( i=1;i<=$num;i=i+1 ))
                 do
                        /usr/sbin/useradd $name$i &>/dev/null
                        echo $pass | /usr/bin/passwd --stdin $name$i &>/dev/null
                 done
                fi
fi
  • while循环

while循环是不定循环,也称条件循环。只要条件判断式成立,循环就会一直继续,直到条件判断式不成立,循环才会停止,这就和for的固定循环就不太一样了。

while [ 条件判断式 ]
  do
    程序
  done

实践:

#!/bin/bash
#从1加到100 

i=1
s=0

while [ $i -le 100 ]
#如果变量i的值小于等于100,则执行循环 
	do
		s=$(( $s+$i ))
		i=$(( $i+1 ))
	done
	echo "The sum is: $s"
  • unit循环

until循环,和while循环相反,until循环时,只要条件判断式不成立,则进行循环,并执行循环程序。一旦循环条件成立,则终止循环。

#!/bin/bash
#从1加到100

i=1
s=0

until [ $i -gt 100 ]
#循环直到变量i的值大于100,循环就停止了 
	do
		s=$(( $s+$i ))
		i=$(( $i+1 ))
	done
	echo "The sum is : $s "

8. continue和break语句

break命令允许跳出所有循环(终止执行后面的所有循环)。
continue命令不会跳出所有循环,仅仅跳出当前循环。

9. I/O重定向

>file stdout转向文件,如果文件不存在,将会创建文件
>>file stdout追加到文件
<file 将文件用作stdin;文件必须存在具有r权限
<<word 从“here”文件中获取输入,直到包含“word”的行

输入重定向:

[root@localhost ~]# wc [选项][文件名]
选项:
-c   统计字节数
-w   统计单词数
-l   统计行数

10. sh中的通配符

  • file *:列出当前目录中所有文件的信息
  • ls *.c:列出当前目录中所有以.c结尾的文件
  • ?通配符:查询某文件名中的字符
  • []通配符:查询文件名中一对[]中的字符
  • file [ab]:包含字符a或b的所有文件名
  • ls [xyz]:列出所有包含x、y或z的文件名
  • ls [a-m]:列出包含a到m范围内字符的所有文件名

11. 命令分组

在sh脚本中,可以用{}或()对命令进行分组。{ls;mkdir abc;ls;}:通过当前sh执行中的命令列表。命令分组的唯一用处是在相同环境下执行这些命令,例如,为分组中的所有命令重定向L/O。更有用的命令分组是(),由subsh(进程)执行。(cd newdir;ls;A=value;mkdir $A):通过subsh进程执行()中的命令。subsh进程可在不影响父sh的情况下更改其工作目录。此外,当subsh进程终止时,subsh中的任何赋值变量都不起作用。

12. eval语句

(1)参数替换:扫描命令行,将任何\(x替换为它的值,但只执行一次,即不能再次替换任何产生的\)符号。
(2)命令替换:用替换行’pwd’。
(3)通配符扩展:当sh执行该文件时,它将new*展开为以abc开头的文件名,这些会把所有以abc开头的文件名复制到目标目录中

2.最有收获的内容

这一章学习了shell编程,最有收获的就是我们能够利用它就是批处理动作,解放双手,避免重复性劳动。通过对shell的学习让我了解到了脚本的好处:

  • 避免开发人员反复进行一些列重复步骤。比如:联网+检查安装包+安装软件+执行命令,如果经常需要做类似的操作,可以考虑将操作写成脚本; (注:IDE为集成开发环境)
  • 提高编译效率。利用编写好 Makefile 文件(shell 脚本) ,只需要一个 make 命令,整个工程就开始自动编译。因为 Makefile 文件中已经事先指明了源文件的编译顺序、依赖关系等重要的编译信息;
  • 不依赖 IDE 就可以实现功能编码, 这在陌生的机器(不具备安装软件的权限) 上显得尤为重要;
  • 方便调用机器下的所有资源。 类似于胶水一样,可以将各类资源(命令、程序、脚本等) 拼接在一起使用。

3. 思维导图

  \#! /bin/bash
  echo \$# = $#
  echo \$* = $*
  echo $1 $9 $10
  echo $1 $9 ${10}
  shift
  echo $1 $9 ${10}
  ~                   

三、一门程序设计语言有哪些必备的要素和技能?这些要素和技能在shell脚本中是如果呈现出来的?

一种编程语言基本上包括:

  • 数据类型
  • 运算符
  • 控制语句

其中数据类型包括:基本类型,集合类型,有了数据类型,才有变量的存在。shell常用的数据类型有 字符串、整数型、数组。
运算符:计算机的本质就是运算,而写程序,也是为了帮助人去计算,所以一种编程语言肯定有运算符。Shell 和其他编程语言一样,支持多种运算符,包括:算数运算符、关系运算符、布尔运算符、字符串运算符、文件测试运算符。
控制语句:人类社会发生的事情,都是有条件的,存在即为正确,因为有它存在的条件。所谓控制语句也就是设定一个条件,当某一个条件发生了,会发生什么事情。shell的控制语句在上方已经明确说明了,这里就不详细阐述了。

四、问题与解决思路

最开始在运行sh脚本时,出现了这个错误:-bash: ./test.sh: 权限不够
我反复校对了网上和我的代码,是一模一样的,但是为什么我的就报错呢?
解决办法:后来查阅资料才发现,问题出在shell脚本上。windows下编译的shell文件,每一行的结尾是\n\r,而在linux下文件的结尾是\n,这个一般用肉眼是看不出来的。利用正则表达式把以\r结束的字符换成空白:

sed -i 's/\r$//'  *.sh       //利用通配符,特别高效

成功解决。

五、实践过程

运行myth脚本,成功执行

尝试条件判断语句

#!/bin/bash                                                                     

read -p "请输入小于100的整数:" num

if [ $num -eq 1 ];then

  echo "和等于: $num"

sum=0

elif [ $num -gt 1 ] && [ $num -lt 100 ];then

  for ((i=1; i<=$num; i++))

  do

  let sum=$sum+$i

  done

  echo "1到$num的和为$sum"

posted @ 2022-09-18 14:35  acacacac  阅读(69)  评论(0编辑  收藏  举报