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"