第十章学习笔记
目录
- sh脚本
- sh脚本与C程序
- 命令行参数
- sh变量
- sh中的引导
- sh语句
- sh命令
- 命令替换
- sh控制语句
- I/O重定向
- 嵌入文档
- sh函数
- sh中的通配符
- 命令分组
- eval语句
- 调试sh脚本
- 苏格拉底挑战
- 问题与解决思路
- 实践过程
1.sh脚本
sh脚本是一个包含sh语句的文本文件,命令解释程序sh要执行该语句。
sh脚本使用chmod +x 文件名执行。
sh脚本的第一行通常以#!组合开始,通常称为shebang。当主sh见到shebang时,会读取脚本所针对的程序名并调用该程序。shebang允许主sh调用适当版本的sh来执行脚本,如果未指定shebang,他将运行默认的sh,即Linux中的/bin/bash。
2.sh脚本与C程序
sh是一个解释程序,逐行读取sh脚本文件并直接执行这些行。如果行是可执行命令且为内置命令,那么sh可直接执行,否则,它会复刻一个子进程来执行命令,并等待子进程终止后再继续,这与它执行单个命令行完全一样。
在sh脚本中,每个变量都是字符串,因此不需要类型。
sh脚本不需要main函数,在sh脚本中,第一个可执行语句是程序的入口点。
3.命令行参数
在sh脚本中,可以通过位置参数$0、$1、$2等访问命令行参数。前10个命令行参数可以作为$0-$9被访问,其它参数必须称为 ${10}- ${n},其中n>10,或者可以通过shift命令查看它们。通常,$0是程序名本身,$1到$n是程序的参数。在sh中,可用内置变量$#和$计数并显示命令行参数。
$#=命令行参数$1到$n的数量
$=所有命令行参数,包括$0
此外,sh还有与命令执行相关的以下内置变量。
$S=执行sh的进程PID
$?=最后一个命令执行的退出状态(如果成功,则为0,否则为非0)
在sh中,特殊字符$表示替换。要按原样使用$,它必须带有单引号或反引号\,类似与\n,\t等等。
4.sh变量
sh变量不用声明,未赋值的sh变量为NULL字符串
如果A是一个变量,则$A是变量A的值(未赋值情况下为NULL)
使用“=”给变量赋值
5.sh中的引导
sh有许多特殊字符,如$、/、*、>、<等。要想将它们用作普通字符,可使用\或单引号来使用它们。通常,\用来引用单个字符,单引号用于引用长字符串。单引号内没有替换。双引号用于保留双引号字符串中的空格,但在双引号内会发生替换。
6.sh语句
sh语句包括所有Unix/Linux命令,以及可能的I/O重定向。
此外,sh编程语言还支持控制sh程序执行的测试条件、循环、case等语句。
7.sh命令
(1)内置命令
sh有许多内置命令,这些命令由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中读取一行并为变量赋值。
set[arg...]:在执行环境中设置变量。
shift:将位置参数$2$3...重命名为$1$2...。
trap[arg][n]:接收到信号n后执行参数。
umask[ddd]:将掩码设置为八进制数ddd的。
wait[pid]:等待进程pid,如果没有给出pid,则等待所有活动子进程。
read命令:当sh执行read命令时,它会等待来自stdin的输入行。它将输入行划分为几个标记,分配给列出的变量。read的一个常见用法是允许用户与正在执行的sh进行交互。在获得输入后,sh可能会测试输入字符串,以决定下一步做什么。
(2)Linux命令
sh可以执行所有的Linux命令。其中,有些命令几乎已经成为sh不可分割的一部分。下面列出并解释了一些命令。
echo命令:echo只是将参数字符串作为行回显到stdout。它通常将相邻的多个空格压缩为一个空格,除非有引号。
expr命令:因为所有的sh变量都是字符串,所以我们不能直接更改它们为数值。可通过expr命令间接更改sh变量的值(数值)。expr是一个程序,它的运行方式如下:
expr string1 OP string2 #OP = any binary operator on numbers
首先,它将两个参数字符串转换为数字,然后对数字执行(二进制)操作OP,再将得到的数字转化为字符串。
同样,expr也可用于对其值为数字字符串的sh变量执行其他算术操作。
管道命令:在sh脚本中经常使用管道作为过滤器。
实用命令:除了上面的Linux命令之外,sh还使用许多其他实用程序作为命令。
awk:数据处理程序
cmp:比较两个文件
comm:选择两个排序文件共有的行
grep:匹配一系列文件的模式
diff:找出两个文件的差异
join:通过使用相同的键来连接记录以比较两个文件
sed:流或行编辑命令;
sort:排序或合并文件
tail:打印某个文件的最后n行
tr:一对一字符翻译
uniq:从文件中删除连续重复行
8.命令替换
在sh中,$A会被替换为A值。同样,当sh遇到‘cmd’(用引号括起来)或$(cmd)时,它会先执行cmd,然后用执行的结果字符串替换$(cmd)。
9.sh控制语句
sh是一种编程语言,支持许多执行控制语句,类似于C语言中的语句。
(1)if-else-fi语句
if [ condition ]
then
statements
else
statements
fi
每个语句必须在单独的一行上,但如果多个语句之间用分号分开,则sh允许多个语句在同一行。
Eg:if [ s1 = s2 ]
if [ s1 < s2 ]
在sh中,左括号[实际上是一个测试程序,它比较两个参数字符串,以确定条件是否为真。需要注意的是,在sh中,0为TRUE,而非0为FALSE,这是因为当sh执行命令时,它会获得命令执行的退出状态,如果执行成功,则为0,否则为非0。运算符-eq、-ne、-lt、-gt等将参数作为整数进行比较。
Eg:if [ “123” -eq “0123”]
除了比较字符串或数值之外,测试程序还可以测试文件操作中经常需要的文件类型和文件属性。
Eg:if [ -e name ] #测试文件是否存在
if [ -f name ] #测试文件是否为REG文件
if [ -d name ] #测试文件是否是DIR
if [ -r name ] #测试文件是否可读
if [ f1 -ef f2 ] #测试文件f1与f2是否相同
复合条件:与在C语言中一样,sh也允许在符合条件中使用&&(与)和||(或),但是语法比C语言更加严谨。条件必须用一对匹配的双括号[[和]]括起来。同时,符合条件也可以通过()进行分组,以执行计算命令。
(2)for语句
for VARIABLE in string1 string2 .... stringn
do
commands
done
在每次迭代中,变量接受一个参数字符串值,并执行关键字do和done之间的命令。
(3)while语句
while [ condition ]
do
commands
done
当条件为真时,sh将重复执行do-done关键字中的命令。预计条件会有变化,所以循环将在某个时间点退出。
(4)until-do语句
until [ $ANS = “give up” ]
do
echo -n “enter your answer”
read ANS
done
(5)case语句
case $variable in
pattern) commands;;
pattern) commands;;
pattern) commands;;
esac
(6)continue和brake语句
工作原理与在C语言中完全相同。
10.I/O重定向
进入sh命令时,我们可以指示sh将I/O重定向到除默认stdin、stdout和sterr以外的文件。I/O重定向有以下形式和含义:
>file stdout转向文件,如果文件不存在,将会创建文件
>>file stdout追加到文件
<file 将文件用作stdin;文件必须存在具有r权限
<<word 从“here”文件中获取输入,直到包含“word”的行
11.嵌入文档
可以指示输出命令从stdin获取输入,将其回显到stdout,直到遇到预先安排的关键字。这种文档被称为嵌入文档。他们通常用在sh脚本中,以生成长块的描述性文本,不需要分别回显每一行。
12.sh函数
sh函数定义为:
func()
{
# function code
}
由于sh逐行执行命令,所以必须在任何可执行语句之前定义sh脚本中所有函数。sh函数的调用方式与sh脚本文件的执行方式完全相同。sh语句
func s1 s2 ... sn
调用sh函数,以参数(字符串)形式传递s1-sn。在被调函数中,参数被引用为$0-$n。通常,$0为函数名,$1-$n是与命令行参数对应的位置参数。函数执行结束时,$?表示其退出状态,如果成功,状态为0,否则状态为非0。 $?值可用函数的显式返回值进行更改。但是,为了测试$?的最后一次执行,必须将其分配给一个变量,然后测试改变量。
13.sh中的通配符
*通配符:可扩展到当前目录中的所有文件
file *:列出当前目录中所有文件的信息
ls *.c:列出当前目录中所有以.c结尾的文件
?通配符:查询某文件名中的字符
file ???:有三个字符的所有文件名
ls *.??:点号后有2个字符的所有文件名
[]通配符:查询文件名中一对[]中的字符
file [ab]:包含字符a或b的所有文件名
ls [xyz]:列出所有包含x、y或z的文件名
ls [a-m]:列出包含a到m范围内字符的所有文件名
14.命令分组
在sh脚本中,可以用{}或()对命令进行分组。
{ls;mkdir abc;ls;}:通过当前sh执行{}中的命令列表。{}命令分组的唯一用处是在相同环境下执行这些命令,例如,为分组中的所有命令重定向I/O
更有用的分组是(),由subsh执行。
(cd newdir;ls;A=value;mkdir $A):通过subsh进程执行()中的命令。subsh进程可在不影响父sh的情况下更改其工作目录。此外,当subsh进程终止时,subsh中的任何赋值变量都不起作用。
15.eval语句
eval [arg1 arg1 ...argn]
eval是sh的一个内置命令。由sh自己执行,不需要复制新进程。
它将输入参数字符串连接到一个字符串中,计算一次,即执行变量和命令替换,然后给出结果字符供sh执行。
16.调试sh脚本
sh脚本可由带有 -x 选项的子sh运行,以进行调试,如
bash -x mysh
子sh可以将在执行命令之前显示要执行的每个sh命令,包括变量和命令替换。允许用户跟踪命令执行。如果出现错误,sh将在错误行上停止并显示错误信息。
17.苏格拉底挑战
sh命令
sh函数
18.问题与解决思路
如何在Linux终端里创建一个sh文件
如何退出调试sh
如何在sh中判断一个变量的数值是不是特定的数
如何在sh中判断一个变量是不是某个字符串
执行sh脚本时出现[[:not found是怎么回事
sh文件需要编译吗
19.实践过程
使用emacs创建sh文件,下面是文件代码
使用bash + 文件名执行sh文件
当输入名字错误且错误次数超过3次就会退出程序
输入名字正确则会表示欢迎并且退出