2021-2022-1 《信息安全系统设计与实现》第三周学习笔记- 20191205张潇

20191205 2021-2022-1-diocs第三周学习笔记

一、任务内容

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

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

知识点归纳以及自己最有收获的内容 (3分)
问题与解决思路(2分)
实践内容与截图,代码链接(3分)
...(知识的结构化,知识的完整性等,提交markdown文档,使用openeuler系统等)(2分)

二、知识点总结

Sh编程学习笔记:

总括框图:

 

1.sh脚本与c程序

sh脚本是一个包含sh语句的文本文件,命令解释程序sh要执行该语句;C程序与其在根本上是不同的。首先,sh是一个解释程序,逐行读取sh脚本文件并直接执行这些行,相反,C程序必须先编译链接到一个二进制可执行文件,然后通过主sh的子进程运行二进制可执行文件;其次,在C程序中,每个变量必须有个类型,相反,在sh脚本中,每个变量都是字符串;最后,每个C程序必须有一个main()函数,每个函数必须定义一个返回值类型和参数,相反,sh脚本不需要main函数。

2.命令行参数

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

3.sh变量:内置变量有PATH、HOME、TERM等,除此之外,用户还可使用任何符号作为sh变量,未赋值的sh变量是NULL字符串。

4.sh命令

常用的内置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中读取一行并为变量赋值;
shift:将位置参数$2 $3...重命名为$1 $2...;
trap[arg][n]:接收信号n后执行参数;
umask[ddd]:将掩码设置为八进制数ddd的;
wait[pid]:等待进程pid,如果没有给出pid,则等待所有活动子进程。

5.Linux命令

sh可以执行所有的linux命令
echo命令:echo只是将参数字符串作为行回显到stdout;
expr命令:因为所有的sh变量都是字符串,所以我们不能直接把它们改为数值;
管道命令:在sh脚本中经常使用管道作为过滤器;
实用命令:awk:数据处理程序;cmp:比较两个文件;comm:选择两个排序文件共有的行;grep:匹配一系列文件的模式;diff:找出两个文件的差异;join:通过使用相同的键来连接记录以比较两个文件;sed:流或行编辑命令;sort:排序或合并文件;tail:打印某个文件的最后n行;tr:一对一字符翻译;uniq:从文件中删除连续重复行。

6.sh控制语句

If-else-if语句:它比较两个参数字符串,以确定条件是否为真,需要注意的是,在sh中,0为TRUE,而非0为FALSE,这与在C程序中完全相反。这是因为当sh执行命令时,它会获得执行的退出状态,如果执行成功,则为0,否则为非0。If-elif-else-fi复合语句条件:与在C语言中一样,sh也允许在复合条件中使用&&(AND)和||(OR),但语法比C语言更加严格,条件必须用一堆匹配的双括号[[和]]括起来。
for语句:sh中的for语句作用类似于C语言中的for循环。

while语句:当条件为真时,sh将重复执行do-done关键字的命令。

until-do、case语句:类似于C语言中的do-until语句。
continue和break语句:它们的工作原理与在C语言中完全相同。

7.I/O重定向

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

8.sh中的通配符

file *:列出当前目录中所有文件的信息
ls *.c:列出当前目录中所有以.c结尾的文件
?通配符:查询某文件名中的字符
[]通配符:查询文件名中一对[]中的字符
file [ab]:包含字符a或b的所有文件名
ls [xyz]:列出所有包含x、y或z的文件名
ls [a-m]:列出包含a到m范围内字符的所有文件名
命令分组:在sh脚本中,可以使用{}或()对命令进行分组

9.eval语句

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

三、最有收获的内容

通过这一章的shell脚本的自学,我想总结一下我之前学过的C语言有哪些必备的要素和技能以及这些要素和技能在sh脚本中是如果呈现出来的?

C语言必备的要素和技能:

第一步:编辑——得到源程序
第二步:编译——得到目标码
第三步:连接——得到可执行代码
第四步:装载运行程序——得到结果
一个简单的C语言程序必须要有:预处理命令、主函数部分、函数参数、被调函数、函数返回值。
对于学习C语言来说,首先,要注意程序的基本结构,程序开头的第一行为“#include stdio.h”, 这句话的意思是,在程序中如果用到了输入输出函数,需要首先在程序中包含文件名为“stdio.h”的标准输入输出的头文件。其次,每一个C语言程序必须要定义一个mian函数,它是程序运行的主函数体,函数中的代码要用“{”和“}”括起来。另外,还需要注意C语言程序的执行过程是编辑、编译、连接和运行,缺一不可。

要素和技能在shell脚本中是如何呈现出来的?

对于同一个程序,shell脚本可以很好的得到结果,但用C语言代码很难实现。尤其是一些查询系统相关信息时,很多时候可以直接用shell命令得到,但c代码却很难得到。
其实可以考虑在c代码中加入与SHELL有关的代码,把一些变量由SHELL来得到。

C语言调用SHELL脚本有三种方法:

1.system()不用自己去产生进程,它就已经封装了,直接加入自己的命令即可;
2.exec需要自己fork进程,然后exec自己的命令;
3.popen()也可以实现执行你的命令,比system开销要小。

具体说明:

system(执行shell 命令)
相关函数 fork,execve,waitpid,popen
表头文件 #include<stdlib.h>
定义函数 int system(const char * string);
函数说明 system()会调用fork()产生子进程,由子进程来调用/bin/sh-cstring来执行参数string字符串所代表的命令,此命令执行完后随即返回原调用的进程。在调用system()期间SIGCHLD 信号会被暂时搁置,SIGINT和SIGQUIT 信号则会被忽略。
返回值:如果system()在调用/bin/sh时失败则返回127,其他失败原因返回-1。若参数string为空指针(NULL),则返回非零值。如果system()调用成功则最后会返回执行shell命令后的返回值,但是此返回值也有可能为system()调用/bin/sh失败所返回的127,因此最好能再检查
errno 来确认执行成功。
在编写具有SUID/SGID权限的程序时请勿使用system(),system()会继承环境变量,通过环境变量可能会造成系统安全的问题。
popen(建立管道I/O)
相关函数 pipe,mkfifo,pclose,fork,system,fopen
表头文件 #include<stdio.h>
定义函数 FILE * popen( const char * command,const char * type);
函数说明 popen()会调用fork()产生子进程,然后从子进程中调用/bin/sh -c来执行参数command的指令。参数type可使用“r”代表读取,“w”代表写入。依照此type值,popen()会建立管道连到子进程的标准输出设备或标准输入设备,然后返回一个文件指针。随后进程便可利用此文件指针来读取子进程的输出设备或是写入到子进程的标准输入设备中。此外,所有使用文件指针(FILE*)操作的函数也都可以使用,除了fclose()以外。
返回值:若成功则返回文件指针,否则返回NULL,错误原因存于errno中。
错误代码:EINVAL参数type不合法。
注意事项:在编写具SUID/SGID权限的程序时请尽量避免使用popen(),popen()会继承环境变量,通过环境变量可能会造成系统安全的问题。

四、问题与解决思路

问题1:如何用shell脚本复制文件?

解决思路:

我想到了复制单个文件的命令是:
cp [options]
而复制文件夹或目录的命令是:
cp [options] source1 source2 source3 …. directory
但我并不理解为什么是这两种命令就可以?后来我通过查找CSDN网站看到一位博主的解释感觉很清楚:
以下是对options的解释:
-a 保留链接和文件属性,递归拷贝目录,相当于下面的d、p、r三个选项组合。
-d 拷贝时保留链接。
-f 删除已经存在目标文件而不提示。
-i 覆盖目标文件前将给出确认提示,属交互式拷贝。
-p 复制源文件内容后,还将把其修改时间和访问权限也复制到新文件中。
-r 若源文件是一目录文件,此时cp将递归复制该目录下所有的子目录和文件。当然,目标文件必须为一个目录名。
-l 不作拷贝,只是链接文件。
-s 复制成符号连结文件 (symbolic link),亦即『快捷方式』档案。
-u 若 destination 比 source 旧才更新 destination。

问题2:Shell内部命令和外部命令的区别?

解决思路:

Linux系统的命令分为内部命令和外部命令两种,内部命令由Shell程序实现,如cd、exit等,Linux的内部命令数量有限,而且绝大部分都很少用到。而每一个Linux外部命令都是一个单独的应用程序,我们非常熟悉的ls、cp等绝大多数命令都是外部命令,这些命令都以可执行文件的形式存在,绝大部分放在目录/bin和/sbin中。因此,对于外部命令,我们可以调用exec系列函数实现,但cd命令无法通过调用exec系列函数实现。作为最为常用的“cd”,必须自己来编写一下。这个命令也比较好编写,但新添加了shell最基本的更改路径功能。另外我查到“pwd”命令也是shell内部命令,但却可以调用exec系列函数执行。经过检查,发现原来目录/bin和/sbin也存在相应的可执行文件,因此可以正常执行。当然这里是调用了相应可执行文件。而cd命令在目录/bin和/sbin中没有相应可执行文件,只能通过自己编程实现。

五、实践内容

一、执行外部命令:ls -al



外部命令:ls -l

二、用Shell脚本求1100之间数字奇数和、偶数和

输入一个小于100的整数,并计算从1到该数之间所有整数的和

代码链接:(https://gitee.com/two_thousand_and_thirteen/codes/ckdqnt6uwsf5hopbm0evj29)

#!/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"

else

  echo "输入错误!"

fi

[zhangxiao@zhangxiao~]# chmod +x test.sh

[zhangxiao@zhangxiao ~]# ./test.sh

截图:

 

输入一个小于100的整数,并计算从1到该数之间的奇数和、偶数和

代码链接:(https://gitee.com/two_thousand_and_thirteen/codes/x8c5f34lytew9n2muk7qj43)

#!/bin/bash

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

if [ $num -eq 1 ];then

  echo "和等于: $num"

sum=0

sum1=0

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

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

  do

  a=$[$i % 2]

  if [ $a == 0 ];then

  let sum=$sum+$i

  elif [ $a == 1 ];then

  let sum1=$sum1+$i

  fi

  done

  echo "1到$num的偶数和为: $sum"

  echo "1到$num的奇数和为: $sum1"

else

  echo "输入错误!"

fi

[zhangxiao@zhangxiao ~]# chmod +x hello.sh

[zhangxiao@zhangxiao ~]# ./hello.sh

截图:

 

 


 


posted @ 2021-09-23 19:54  张灯结彩,潇潇暮雨  阅读(88)  评论(0编辑  收藏  举报