简介
Shell是一个命令解释器,用户输入命令来获得自己想要的结果,但是终端中输入的命令很难进行高级语言的选择、循环等操作。不过Shell程序可以存放在文件上,称为Shell脚本(虽然Linux文件不以后缀名区分文件类型,但是一般编写Shell脚本时文件名会命名为以.sh结尾)。在脚本中可以较方便的进行类似高级语言的操作。
最简单的Shell脚本

我们都知道,直接在终端输入echo命令是回显参数,把echo命令放在shell脚本中有相同的效果。
设置成可执行文件
变量
Shell脚本中的变量直接使用=便可创建,使用$解析变量名。{}是分组命令,表示H是一个变量,这里不加也可以。

特殊变量
$#:除脚本名外,命令行上参数的个数。$*:表示在命令行上实际给出的所有实参。- 如:
exam3.sh A B C D E F G H I J K。$#是11。$*是: A B C D E F G H I J K
- 如:
$n:表示命令行上第n个参数$0表示文件名$1表示第一个参数 …
$@:表示在命令行上实际给出的所有实参。- 如:
exam3.sh A B C D E F G H I J K。$@就是: “A” “B” “C” “D” “E” “F” “G” “H” “I” “J” “K”
- 如:
$$:当前进程的进程号$!:上一个后台命令对应的进程号。$?:上一条前台命令执行后的返回值。
算术运算
执行算术运算需要使用let,如let c=$a+$b。可以使用c=$(($a+$b))代替。其中算术运算符及优先级等同于C语言。同时多了个**表示幂运算。(运算符前后不要有空格)

从命令行读入参数
直接使用read,命令行中的参数会读到read后面跟的参数(相当于变量)里。

读入时输出提示信息:

引号
- 双引号:由双引号引起来的字符(除
$、`和`)都被当做普通字符对待。`$表示变量替换;`表示命令替换;\之后的字符只有是$、`、`双引号`、或换行符之一时会成为转义字符。其他情况都是\本身。

- 单引号:单引号引起来的字符都是普通字符。特殊字符也失效。
- 倒引号:被到引号引起来的字符被解释为命令。如上上图中所示。
数组
变量之间使用空格隔开各个元素。如果元素中有空格,使用双引号引起来。

测试条件
任何命令都可以作为条件,shell会执行这个命令并检查返回值,如果命令成功(返回值为0),表示真。
test <条件>:如test n1 -eq n2[ 条件 ]:如[ n1 -eq n2 ]
有关文件方面的测试
-r 文件名:真 <==> 文件存在并且是用户可读-w 文件名:真 <==> 文件存在并且是用户可写-x 文件名:真 <==> 文件存在并且用户可执行-f 文件名:真 <==> 文件存在且是普通文件-d 文件名:真 <==> 文件存在且是目录文件-s 文件名:真 <==> 文件存在且长度大于0
有关字符串方面的测试
-z s1:真 <==> 字符串长度为0-n s1:真 <==> 字符串长度大于0s1:真 <==> 字符串不是空字符串s1 = s2(在“=”前后应有空格):真 <==> 字符串相等s1 != s2:真 <==> 字符串不等s1 < s2:真 <==> 按字典顺序s1在s2之后s1 > s2:真 <==> 按字典顺序s1在s2之前
数值方面的测试
n1 -eq n2:真 <==> 数值相等n1 -ne n2:真 <==> 数值不等n1 -lt n2:真 <==> n1小于n2n1 -le n2:真 <==> n1小于或等于n2n1 -gt n2:真 <==> n1大于n2n1 -ge n2:真 <==> n1大于或等于n2
逻辑运算符
!:逻辑非-a:逻辑与-o:逻辑或(表达式):圆括号括起来表示为一条语句
选择结构

循环结构

break & continue
和C语言一致。
shift
参数跳转命令:不跟数组默认跳转1位,跟了跳转n位。
| 命令行 | ex.sh | A | B | C | D | E | F |
|---|---|---|---|---|---|---|---|
| 原位置参数 | $0 | $1 | $2 | $3 | $4 | $5 | $6 |
| 移位后参数 | $0 | $1 | $2 | $3 | $4 | $5 |
还可以用于循环结构的done上面,表示每次选择指定参数。
参数置换变量
| 格式 | var1为空 | var1不空 |
|---|---|---|
var2=${var1:-str} |
var2=str。var1不变 | var2=$var1。var1不变 |
var2=${var1:=str} |
var2=var1=str | var2=$var1。var1不变 |
var2=${var1:+str} |
var2为空。var1不变 | var2=str。var1不变 |
var2=${var1:?str} |
输出:“shell 脚本名:var1:str”并退出shell。var2不变 | var2=$var1。var1不变 |
ex1
编写ex1.sh,参数为一个大于 20 的正整数。先检查参数是否符合要求。如果不符合要求,请给出提示;如果符合要求,输出这个参数的平方。

ex2
编写ex2.sh,首先显示当天日期,然后查找给定的用户是否在系统中工作(who 命令)。如果在系统中,就输出一条欢迎语句(例如 hello,xxxx!);如果不在系统中,就输出一条语句(waiting for xxx!)

ex3
编写 ex3.sh,该脚本接受一个参数。若改参数不是目录,则给出提示信息;否则使用ll命令列出该目录下的内容,并输出有多少个子目录(d开头),多少个普通文件(-开头)。

ex4
编写 ex4.sh,将第一个参数指定的内容 copy 到第二个参数指定地点。
- 若第一个参数是目录,自动添加
-r选项(即把目录下的所有内容都 copy 过去); - 若第一个参数是普通文件,则将其 copy 到指定地点;
- 若第一个参数指定的文件或目录不存在,则报错;
- 若第二个参数指定的文件或目录已经存在,则提示是否替换,若选择 yes,则先删除原来的文件或目录,然后再执行 copy 操作,否则放弃。


ex5
编写 ex5.sh。检查命令行的第一个参数是否是-b或者-s。
- 如果是
-b,则计算由第二个参数指定的文件中以 b 开头的行数。 - 如果是
-s,则计算由第二个参数指定的文件中以 s 开头的行数。否则显示选择有错的信息。

ex6
编写 ex6.sh。该脚本需要输入两个文件的名称,然后由用户选择相应的操作(若两个参数中任何一个不是普通文件,则报错)。

cat:输出两个文件的内容

statistic:统计两个文件分别有多少行

merge:将第 1 个文件的内容合并到第 2 个文件后面

copy:将第 1 个文件的内容 copy 到第 2 个文件(覆盖原文件)

bye:退出

1ex
编写 1ex.sh,利用 for 循环将当前目录下的.c 文件移动到指定的目录下,完成后显示指定目录下的文件内容,并按文件从小到大排序。(ll -r -S)

2ex
编写 2ex.sh,显示 Fibonacci 数列的前 10 项及其总和。

3ex
编写 ex3.sh,判断给定的参数是否是素数。

4ex
编写 ex4.sh,将给定的参数转换成二进制表示。

5ex
ex5.sh假设存在一个/homework的文件夹,其中包含一个 studentlist.csv的文件,当中存放了若干学生的学号,每个一行。例如:150341101、150341102、150341105、150341106,编写 ex11.sh。查看/homework 文件夹下学生是否提交了作业,假设作业名的格式为:学号_homework.txt。最后输出没提交作业的学号名单。

