《Unix/Linux系统编程》教材第10章学习笔记

发布时间 2023-09-24 10:59:33作者: 20211424罗杰逊

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

必备要素和技能:

  1. 数据类型和变量:用于存储和处理数据的基本单元。
  2. 控制结构:用于控制程序流程的结构,如条件语句、循环语句等。
  3. 函数和模块:用于封装代码块,实现代码的复用和组织。
  4. 输入/输出:用于与用户交互和输出结果的功能。
  5. 异常处理:用于处理程序运行时出现的错误和异常情况。
  6. 内置函数和库:提供了一些常用的函数和工具,方便开发人员使用。

Shell脚本呈现:

  1. 数据类型和变量:Shell脚本中的变量可以是字符串、数字、布尔值等类型。
  2. 控制结构:Shell脚本中的控制结构包括条件语句(如if、elif、else)和循环语句(如for、while、until)等。
  3. 函数和模块:Shell脚本中可以使用函数来封装代码块,实现代码的复用和组织。同时,Shell脚本也支持使用外部的命令和工具,实现更多的功能。
  4. 输入/输出:Shell脚本中可以使用标准输入/输出(stdin、stdout、stderr)来与用户交互和输出结果。
  5. 异常处理:Shell脚本中可以使用条件判断和循环语句来处理程序运行时出现的错误和异常情况。
  6. 内置函数和库:Shell脚本中提供了一些内置函数,如date、echo、cut等,可以方便地进行日期处理、输出文本、截取字符串等操作。同时,Shell脚本也支持使用外部的命令和工具,实现更多的功能。

第10章:sh编程

sh脚本
sh脚本是一个包含sh语句的文本文件,命令解释程序sh要执行该语句。
可以创建一个文本文件:mysh.sh

#! /bin/bash
# comment line
echo hello

使用chmod +x mysh使其可执行。
#!开头一般称为shebang,若未指定shebang,则将运行默认sh,即Linux中的/bin/bash。当bash执行mysh脚本时,将会打印hello。

sh脚本与C程序

首先,sh是解释程序,逐行读取sh脚本文件并直接执行这些行。如果行是可执行命令且为内置命令,那么sh可直接执行。否则,它会复刻一个子进程执行命令,并等待子进程终止后再继续,这与它执行单个命令行完全一样。子进程终止后再继续,这与它执行单个命令行完全一样。相反,C程序必须先编译链接到一个二进制可执行文件,然后通过主sh的子进程运行二进制可执行文件。其次,在C程序中每个变量必须有一个类型,例如char、int、float、派生类型(如struct)等。相反,在sh脚本中,每个变量都是字符串。因此不需要类型,因为只有一种类型,即字符串。最后,每个C程序必须有一个main()函数,每个函数必须定义一个返回值类型和参数(如有)。相反,sh脚本不需要main函数。在sh脚本中,第一个可执行语句是程序的入口点。

命令行参数
可使用与运行sh命令完全相同的参数调用sh脚本,如:
mysh one two three
在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中,特殊字符$表示替换。要按照原样使用$,它必须带有单引号或反引号\,类似于C中的\n。在第2、3行中,,每个$按原样打印,没有替换。第4行,$1和$9打印正确,$10确被打印成了abc0。第6行将位置参数向左移动一次,使得$2=$1、$3=$2等。$9变成了L。

sh变量
sh有许多内置变量,如 PATH、HOME、TERM等。除了内置变量外,用户还可使用任何符号作为sh变量。不需要声明。所有的sh变量值都是字符串。未赋值的sh变量是NULL字符串。sh变量可用以下方法设置或赋值:
variable=string # NOTE: no white spaces allowed between tokens
如果A是一个变量,则$A是变量的值。

sh中的引号
sh中有许多特殊字符,例如:$、/、*、>、<等,要想用作普通字符需要使用\(转义符)或单引号''来引用它们。

通常,/用于引用单个字符。单引号用于引用长字符串。单引号内没有替换。双引号用于保留双引号字符串中的空格,但在双引号内会发生替换。

sh语句
sh语句包括所有Unix/Linux命令,以及可能的I/O重定向。例如:

ls
ls > outfile
date
cp f1 f2
mkdir newdir
cat < filename

此外,sh编程语言还支持控制sh程序执行的测试条件、循环、case等语句。

sh命令

  • 内置命令
    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进行交互,例:

echo -n "enter yes or no:"	#wait for user input line from stdin
	read ANS					#sh reads a line from stdin
	echo $ANS					#display the input string

在获得输入后,sh可能会测试输入字符串,以决定下一步做什么。

  • Linux命令
    sh可以执行所有的Linux命令。
    echo:echo只是将参数字符串作为行回显到stdout。它通常将相邻的多个空格压缩为一个空格,除非有引号。

expr:因为所有的sh变量都是字符串,所以不能直接把它们改为数值,但可通过expr命令间接更改sh变量的值(数值),例如:

I=123
I=$(expr $I + 1)

管道命令:在sh脚本中经常使用管道作为过滤器,例:

ps -ax | grep httpd
	cat file | grep word

实用命令:
awk:数据处理程序。
cmp:比较两个文件。
comm:选择两个排序文件共有的行。
grep:匹配一系列文件的模式。
diff:找出两个文件的差异。
join:通过使用相同的键来连接记录以比较两个文件。
sed:流或行编辑命令。
sort:排序或合并文件。
tail:打印某个文件的最后n行。
tr:一对一字符翻译。
uniq:从文件中删除连续重复行。

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

sh控制语句

  • if-else-if语句
    1.if-else-fi语句语法:
if[condition]	#NOTE:must have white space between tokens
	then
		statements
	else		#as usual, the else part is optional
		statements
fi				#each if must end with a matching fi
每个语句必须在单独的一行上。如果多个语句用分号分开,允许在在同一行。

通常写为:

if[condition]; then
		statements
	else		
		statements
fi	

if-elif-else-fi复合语句(使用elif而不是else if):

if[condition1]; then
		commands
	elif[condition2]; then
		commands
	#additional elif[condition3]; then etc.
	else		
		commands
fi	

复合条件:&&和||,但是需要用一对匹配的双括号[[和]]括起来。和c一样,可以使用()进行条件分组。

  • for语句
for VARIABLE in string1 string2 .... stringn
	do
		commands
	done

每次迭代中,变量接受一个参数的字符串值,并执行关键字do和done之间的命令。

  • while语句
while[condition]
	do
		commands
	done

当条件为真时,sh将重复执行do-done关键字中的命令。预计条件会有变化,所以循环将在某个时间点退出。

  • until-do语句
    类似于c中的do—until语句
until[$ANS="give up"]
	do
		echo -n "enter your answer:"
		read ANS
	done
  • case语句
    很少使用
case $variable in
	pattern1) commands;;	#note the double semicolons;;
	pattern2) command;;
	patternN) command;;
esac
  • continue和break语句
    与C语言一样,continue重启最近循环的下一次迭代,break退出最近循环。与C语言中完全相同。

I/O重定向
当进入sh命令时,可以指示sh将I/O重定向到除默认stdin、stdout和sterr以外的文件。I/O重定向有以下形式和含义:

file stdout转向文件,如果文件不存在,将会创建文件。

file stdout追加到文件。
<file 将文件用作stdin;文件必须存在并具有r权限。
<<word 从“here”文件中获取输入,直到只包含“word”的行。

嵌入文档
可以指示输出命令从stdin获取输入,将其回显到stdout,直到遇到预先安排的关键字。
这些文档通常被称为嵌入文档。它们通常用在sh脚本中,以生成长块的描述性文本,不需要分别回显每一行。

sh函数
sh函数定义为:

func()
{
	#function code
}

由于sh逐行执行命令,所以必须在任何可执行语句之前定义sh脚本中的所有函数。与C不同,sh脚本中无法声明函数原型。sh函数调用方式与sh脚本文件的执行方式完全相同。sh语句
func s1 s2 ... sn
调用sh函数,以参数(字符串)形式传递s1~sn。在被调函数中,参数被引用为$0、$1到$n。通常,$0是函数名,$1到$n是与命令行参数对应的位置参数。函数执行结束时,$?表示其退出状态,如果成功,状态为0,否则,状态为非0。$?值可用函数的显式返回值进行更改。但是,为了测试$?的最后一次执行,必须将其分配给一个变量,然后测试该变量。

sh中的通配符
星号通配符:sh中最有用的通配符是*,可扩展到当前目录中的所有文件。
?通配符:查询某文件名中的字符
[]通配符:查询文件名中一对[]中的字符。

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

eval语句
eval [arg1 arg1 .. argn]
eval是sh的一个内置命令,它由sh自己执行,而不需要复刻新进程。它将输入参数字符串连接到一个字符串中,计算一次,即执行变量和命令替换,然后给出结果字符串供sh执行。
注意:使用eval可省去一些替换语句,但也可能使代码难以理解。因此应当避免使用任何不必要的eval。

调试sh脚本
sh脚本可由带有-x选项的子sh运行,以进行调试,如:
bash -x mysh
子sh将在执行命令之前显示要执行的每个sh命令,包括变量和命令替换。它允许用户跟踪命令执行。如果出现错误,sh将在错误行上停止并显示错误消息。

gpt苏格拉底提问

  • 内置命令

  • Linux命令

sh脚本练习及代码