linux 环境中的程序设计基础

109
Linux 环环环环环环环环环环 环环 vi 环环环环

Upload: leila-hebert

Post on 30-Dec-2015

118 views

Category:

Documents


8 download

DESCRIPTION

Linux 环境中的程序设计基础. 使用 vi 编辑文件. vi 编辑器使用. vi editor 是一个全屏幕文本编辑器 所有的 Linux 版本都提供了这一编辑器 在 Linux 系统中使用 vi 来编写文本文件 vi 也是 Unix 世界里极为普遍的全屏幕文本编辑器. vi 的启动. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Linux 环境中的程序设计基础

Linux 环境中的程序设计基础

使用 vi编辑文件

Page 2: Linux 环境中的程序设计基础

vi 编辑器使用

vi editor 是一个全屏幕文本编辑器

所有的 Linux 版本都提供了这一编辑器

在 Linux 系统中使用 vi 来编写文本文件

vi 也是 Unix 世界里极为普遍的全屏幕文本编辑器

Page 3: Linux 环境中的程序设计基础

vi 的启动

格式:vi [options] [filename]

功能:自动载入所要编辑的已有文件,或开启一个新文件

输出:如果未指定选项或文件,将进入vi程序并开始编辑一个新缓冲区。当屏幕的左边出现“~”号,表示本行为空行。

常用选项 /功能:

+n 从第n行开始编辑文件

+/exp 从文件中匹配字符串exp的第一行开始编辑

Page 4: Linux 环境中的程序设计基础

shell 程序文件的建立实例

用 vi 编辑器建立 shell 程序文件 shex1 的步骤: ① 键入命令“ vi shex1” ,启动 vi ; ② 按命令“ i” ,进入 vi 的插入状态; ③ 输入程序文件内容;

clear cal 1 98 cal 2 98 cal 3 98

④ 按 <Esc> 键,再键入“ :” ,切换到 vi 的命令状态; ⑤ 在“ :” 后键入命令“ wq” ,即保存文件内容后,退出 vi

Page 5: Linux 环境中的程序设计基础

vi 的 2 种状态

进入 vi 后有 2 种状态:“编辑”状态和“一般命令”状态。  编辑状态  在此状态下输入文本编辑命令,输入文本文字信息。  一般命令状态 在此状态下键入的都是命令,这些命令用来下达一些文件存档、以及离开 vi 等等的操作指令。  当进入 vi ,先在编辑状态,等待编辑命令的输入。 2 种状态的转换  任何情况下,按“ ESC” 键就进入编辑命令状态,光标定位在文档中,等待编辑命令的输入。  在编辑命令状态下,按“:”键,进入一般命令状态,屏幕左下方出现“ :” 提示符,等待输入一般命令。

Page 6: Linux 环境中的程序设计基础

编辑状态下的文字输入

在编辑状态下,有光标闪动,这是文字插入点。在编辑状态下,输入以下编辑命令,便进入插入模式:

a :从光标所在位置后开始追加文字,光标后的文字随追加的文字向后移动。

i:从光标所在位置前开始插入文字,光标后的文字随追加的文字向后移动。

o:在光标所在行下方新增一行,并进入编辑状态。 编辑状态下输入文字时,有 2 种模式:“插入”与“改写”,按“ Insert” 键即可转换状态。编辑状态下按“ ESC” 键,就退出插入模式。此时输入“ /” ,进入一般命令状态,然后输入欲搜索的字符再按回车键,光标将指向文本中与字符匹配的地方。

Page 7: Linux 环境中的程序设计基础

   vi 下有多种编辑命令可完成以下功能:删除与恢复修改剪贴板查找与替换光标移动寻找、搜索……  但记住编辑命令是麻烦的,实际上,在命令模式下移动方向键就可以移动光标;按 [Delete] 键与[backspace] 键就可删除字符。

Page 8: Linux 环境中的程序设计基础

  在一般命令状态下,键入以下命令:

q 结束编辑(打开的文档未作任何修改),退出 vi

q! 放弃编辑不作保存(打开的文档已编辑过),退出 vi

wq 保存当前文件后退出 vi

wq! 强制性保存当前文件(包括只读文件)后退出 vi

w [filename] 用于对新建文件(直接键入 vi )或当前 正编辑的文件作保存后继续编辑e <filename> 当前没有未保存的修改,则进入由 < 文

件名 > 指出的文件进行编辑e! <filename> 即使有未保存的修改,也不作保存,进

入由 < 文件名 > 指出的文件进行编辑

退出 vi

Page 9: Linux 环境中的程序设计基础

删除与恢复

在编辑状态下,对文档内容作删除操作的命令:

x 删除当前光标所在位置的字符,功能同“ Del” 键。

dw 删除当前光标所在位置的单词。

dd 删除当前光标所在的行,注意: dd 是按两次 d。

d$ 删除当前光标所在位置至本行结尾的所有字符。

dG 删除当前光标所在位置至文件结尾处的所有字符。 恢复是指对误删除的恢复,在编辑状态下,若要恢复误删除的内容,则使用命令 u。

Page 10: Linux 环境中的程序设计基础

修改

R 键入 R ,然后键入修改后的单词。r 改写光标所在处的单个字符。~ 用来改变光标所在处的字符的大小写。

Page 11: Linux 环境中的程序设计基础

剪切、复制、粘贴

yy 将光标所处行选中,并复制到系统剪贴板上。

c 即 cut ,是将光标所处行移到剪贴板上,原行内容在屏幕上消失。

p 即 paste ,是将剪贴板上的内容复制到光标所在行。

Page 12: Linux 环境中的程序设计基础

查找和替换

vi 中也可进行查找和替换,这无疑为修改相同的字符串带来了方便, vi 的查找和替换功能是在命令方式下实现的,其命令如下:

s / 需替换内容 / 修改后内容 / 需改内容所在行号注意:在查找替换操作前,必须将光标移至文件首。

例:

用“ After completion” 来替换“ Once I have completed it.”

Page 13: Linux 环境中的程序设计基础

shell 程序运行的 2 种方法

运行 shell 程序有两种方法: 在 shell 环境下,将 shell 程序文件作为子 shell 程

序被调用执行

$sh <shell 程序文件名 > [< 参数 1> < 参数 2>

……]

例:$sh shex1

Page 14: Linux 环境中的程序设计基础

将 shell 程序文件视作命令来执行(因此, shell 程序文件可以看作是将各种命令组合在一起而形成的新命令),此时必须赋予 shell 程序文件执行权限

$ <shell 程序文件名 > [<参数 1> <参数 2> ……]

例:① $ chmod a+x shex1 给程序文件赋予可执行属性

② $ /home/user1/shex1 以完整的路径名键入程序名或 $ ./shex1 以相对路径名键入程序名

Page 15: Linux 环境中的程序设计基础

带参数的运行命令

运行命令中有 [ 参数 ] 和无 [ 参数 ] 的 2 种情况,分别称为带参数的运行命令和不带参数的运行命令

在 shell 程序中一般使用的形参为: $0 、 $1 、 $2 、…… $9 ,共 10 个

当程序运行时,命令行中的 < 参数 1> 、 < 参数2>… 依次赋值给 $1 、 $2 、…,通常称运行命令中所带的参数为实参

$0 是一个特殊的形参,其值规定为当前运行的 shell程序命令本身

Page 16: Linux 环境中的程序设计基础

例:建立 shell 程序 shex3 ,其内容为: clear

cal $1 98

cal $2 98

cal $3 98

执行时输入命令的形式为:$ sh shex3 1 2 3

第一个实参值是 1 ,运行时代换给程序中的形参 $1,

第二个实参值是 2 ,运行时代换给程序中的形参 $2,

第三个实参值是 3 ,运行时代换给程序中的形参 $3

Page 17: Linux 环境中的程序设计基础

命令 shift 作用

由于形参个数有限(一般为 10 个),当参数较多时,可通过命令 shift 来移动形参与实参的对应关系执行一次 shift 后, $1 、 $2 、……变为依次与< 参数 2> < 参数 3>…… 对应再执行一次 shift 后, $1 、 $2 、……变为依次与< 参数 3> < 参数 4>…… 对应,依此类推

Page 18: Linux 环境中的程序设计基础

例:建立 shell 程序 shex2 ,其内容为: echo $0 $1 $2 shift echo $0 $1 $2运行时情况如下:# /root/shex2 yesterday today tomorrow/root/shex2 yesterday today/root/shex2 today tomorrow#可见: $0 始终是当前运行的 shell 程序命令本身,即 /root/shex2

Page 19: Linux 环境中的程序设计基础

内部变量:由系统提供,用户不能修改。

用户变量:由用户建立和修改,在 shell 脚本编写中会经常用到。是在当前 shell 中使用的局部变量,不能被在 shell 下运行的其他命令或其它 shell 程序使用 环境变量:这些变量决定了用户工作的环境,它们不需要用户去定义,可以直接在 shell 中使用,其中某些变量用户可以修改。它可将值传给 shell 运行的其他命令或 shell 程序使用,也就是说系统变量是全局变量

shell 变量大致可以分为三类:内部变量、用户变量和环境变量。

Shell 变量

Page 20: Linux 环境中的程序设计基础

变量名 含义HOME 用户主目录UID 当前用户的标识符,取值是由数字构成的字符串USER 用户名,与登录名相同PWD 当前工作目录的绝对路径名,该变量的取值随 cd

命令的使用而变化MAIL 用户的邮箱路径名HOSTNAME 计算机的主机名INPUTRC 默认的键盘映像SHELL 用户所使用的 shell 的路径名HISTSIZE history 所能记住的命令的最多个数

常见的 Shell 变量

Page 21: Linux 环境中的程序设计基础

变量名 含义PATH shell 查找用户输入命令的路径 ( 目录列

表 ) , shell 将按 PATH 变量中给出的顺序搜索这些目录,找到的第一个与命令名称一致的可执行文件将被执行

PS1 shell 一级命令提示符(主提示符)在特权用户下,默认的主提示符是 # ;在普通用户下,默认的主提示符是 $

PS2 shell 二级命令提示符在 shell 接收用户输入命令的过程中,如果用户在输入行的末尾输入“ \” 然后按回车键,或者当用户按回车键 shell 判断出用户输入的命令没有结束时,就显示这个辅助提示符,默认是“ >”

常见的 Shell 变量

Page 22: Linux 环境中的程序设计基础

PATH 变量是最重要的环境变量之一。当用户在命令行中输入命令时, shell 就会根据该变量定义的路径(目录)和顺序,查找并执行该命令。如果没有正确设置 PATH 变量,则必须输入完整的路径名来运行某个命令。

用户可以根据需要修改环境变量 如: HISTSIZE , PATH , PS1 , PS2 等

在 Linux 下输入命令的两种方式: 直接在命令行中输入命令:根据 PATH 查找该命令 输入完整的路径名

Shell 变量

Page 23: Linux 环境中的程序设计基础

查询当前 shell 中的环境变量: env

env

查询某个变量的值: echo

echo ${ 变量名 }

Shell 变量查询

Page 24: Linux 环境中的程序设计基础

重设 PS1 和 PS2 的设置

例: export PS1=“\t\w\$”

在 bash 中,有两个级别的命令输入提示:

export使变量的值对当前 shell 及其所有子进程都可见

命令提示符

一级提示符是当 bash 等待输入命令时所出现的提示符,由环境变量 PS1 控制,缺省值为 “ $” ; 二级提示符是在 bash 执行一个命令后,需要用户进一步输入才能完成次命令时,所出现的提示符,由环境变量 PS2 控制,缺省值为 “ >” 。

Page 25: Linux 环境中的程序设计基础

在创建提示符时,可以使用下面的特殊字符:

\! 显示命令的历史编号 \h 显示机器的主机名\# 显示命令的命令编号 \s 显示当前使用的 shell

\\ 显示一个反斜杠 \u 显示用户名\n 显示一个换行符 \W 显示当前目录名\d 显示当前的日期 \w 显示当前目录完整路

径名\t 显示当前的时间\$ 用户显示“ $” 提示

符\nnn 显示与八进制 nnn

相对应的字符

命令提示符

Page 26: Linux 环境中的程序设计基础

在启动交互式会话过程中,在出现提示符前,系统会读取几个配置文件,并执行这些文件中的命令。所以这些文件可以用来定制 bash 环境。如:设置 shell 变量值或建立别名等。 bash 配置文件:

在命令行中设置和修改的变量值,只在当前的 shell 中有效。一旦用户退出 bash ,所做的一切改变都会丢失。

bash 配置文件

bash 配置文件

/etc/profile ~/.bash_profile~/.bash_login~/.profile

~/.bashrc

Page 27: Linux 环境中的程序设计基础

/etc/profile

bash 配置文件

读取 /etc/profile 文件后, bash 将在用户主目录中按顺序查找以下文件,并执行第一个找到的文件:

Linux 系统中的全局 bash 启动脚本,任何用户登录系统时 /etc/profile 都会被执行。通常用来设置标准 bash

环境,但修改该文件需 root 权限。

~/.bash_profile~/.bash_login~/.profile

在这些文件中,用户可以定义自己的环境变量,而且能够覆盖在 /etc/profile 中定义的设置。

Page 28: Linux 环境中的程序设计基础

bash 启动后,将读入配置文件 ~/.bashrc ,并执行这个文件中的所有内容。

bash 配置文件

另外,还可以从另一个 shell 或者 bash 自身启动一个新的 bash ,这种过程称为非登录交互式,启动新 bash

的命令为 bash ,此时所读入的唯一 bash 配置文件是 ~/.bashrc

通常,个人 bash 环境设置都定义在 ~/.bashrc 文件里

Page 29: Linux 环境中的程序设计基础

变量赋值: 等号两边不能有空格 如果要给变量赋空值,可以在等号后面跟一个换行符

variable=value

变 量

变量命名 变量名必须以字母或下划线开头,后面可以跟字母、数字 或下划线。任何其它字符都标志变量名的结束。 变量名关于大小写敏感。

变量类型: 根据变量的作用域,变量可以分为局部变量和环境变量 局部变量只在创建它们的 shell 中可用。而环境变量则 在所有用户进程中可用,通常也称为全局变量。

Page 30: Linux 环境中的程序设计基础

变量赋值

格式: < 变量名 > =< 字符串 >功能:将等号右边的字符串赋给等号左边的变量变量名可以由任意字符、数字或下划线组成,但数字不能作为变量名的首字符。变量名不能包含空格、惊叹号字符变量名不能使用 shell 中保留的关键词等符号变量名不能多于一个词,因为 shell 使用空格分析命令、定界命令名和参数,所以若字符串中含有空格,则在字符串上加上引号例: name1=MARY

name2="X Window"

Page 31: Linux 环境中的程序设计基础

显示变量的值echo $variable 或 echo ${variable}

清除变量unset variable

显示所有变量set

例:myname=jypanecho $mynameunset mynameecho $myname

变 量

Page 32: Linux 环境中的程序设计基础

变量举例

Page 33: Linux 环境中的程序设计基础

例: $ 是特殊变量,用来存储当前运行进程的 PID

局部变量和作用域 变量的作用域

是指变量在一个程序中那些地方可见。对于 shell 来说,局部变量的作用域限定在创建它们的 shell 中。

Page 34: Linux 环境中的程序设计基础

引用变量

格式: $< 变量名 >功能:引用变量的值。只要在变量名前加上“ $” 字符,变量名即将变量值取代例:# name2=$name1 将变量 name1 值赋予变量 name2 # echo $name1 在屏幕上显示变量 name1 的值

Page 35: Linux 环境中的程序设计基础

单引号和双引号允许用户一次把几个字符引起来。双引号不可以把美元符 $ 引起,因为 $ 操作符将导出变量所代表的值。如果已包含在双引号中有 $ 字符,并紧跟变量名,则在执行 shell 命令时,字符串中的变量将被变量所代表的数值所取代例:# winner=david# notice="The person who won is $winner."# echo $notice

显示结果为: The person who won is david.

Page 36: Linux 环境中的程序设计基础

但若用户不希望求出包含在字符串中的变量的值,在这种情况下,应该使用单引号作为字符串的定界符。单引号将抑制任何变量值,并把美元符看成另一个字符例:# winner=david# notice='The name is in the $winner variable.'# echo $notice

显示结果为: The name is in the $winner

variable.

Page 37: Linux 环境中的程序设计基础

若要将美元符使用,可以加上反斜杠 \ 来引导 $ 操作符例:# winner=david# result="$winner won \$100.00"# echo $result

显示结果为: david won $100.00.

Page 38: Linux 环境中的程序设计基础

释放变量

格式: unset < 变量名 >功能:释放一个现存的 shell 变量。要慎用 unset * ,因为它将删除全部 shell 变量例:# unset name1

Page 39: Linux 环境中的程序设计基础

变量被创建时所处的 shell 称为父 shell 。如果在父 shell 中启动一个新的 shell (或进程),则该 shell (

或进程 ) 被称为子 shell ( 或子进程 ) 。

环境变量 环境变量 作用域包含创建它们的 shell ,以及从该 shell 产生的任意子 shell 或进程。 按照惯例,环境变量通常使用大写。 环境变量是已经用 export 内置命令输出的变量。

环境变量就象 DNA ,可以从父亲传递给儿子,再到孙子,但不能从子进程传递给父进程。

Page 40: Linux 环境中的程序设计基础

export :使变量的值对当前 shell 的所有子进程都可见。

说明:设置或显示环境变量。

语法: export [ 选项 ] [ 变量名称 ]=[ 变量设置值 ]

该命令的各选项含义如下:

-f 代表 [ 变量名称 ] 中为函数名称;

-n 删除指定变量,变量实际未删除,只是不输出到后续指令的执行环境中;

-p 列出所有 shell赋予程序的环境变量。

Page 41: Linux 环境中的程序设计基础

环境变量举例

export variable=value

设置环境变量

variable=value; export variable

例:

export -n variable

export -p

将全局变量转换成局部变量

列出所有全局变量

Page 42: Linux 环境中的程序设计基础

printf 可用来按指定的格式输出变量printf format 输出参数列表

printf 的打印格式与 C 语言中的 printf 相同printf "%-12.5f\n" 123.456

format

以 % 开头 flag field width precision

格式符

-: 左对齐+: 输出符号0: 空白处添 0空格 : 前面加一空格

字段宽度 小数点后输出位数

printf 命令

Page 43: Linux 环境中的程序设计基础

printf 命令的格式说明符c 字符型 g/G 浮点数(自动)d 十进制整数 o 八进制e/E 浮点数(科学计数法) s 字符串f 浮点数(小数形式) x/X 十六进制

format 中还可以使用\a 警铃 \t 水平制表符\b 退后一格 \v 垂直制表符\n 换行 \\ 反斜杠\f 换页 \” 双引号\r 回车 %% 百分号

printf 命令

Page 44: Linux 环境中的程序设计基础

printf "The number is: %.2f\n" 100

printf "%-20s|%12.5f|\n" "Joy" 10

printf "%-10d%010o%+10x\n" 20 20 20

printf "%6d\t%6o\"%6x\"\n" 20 20 20

printf 命令举例

例:

Page 45: Linux 环境中的程序设计基础

位置参量是一组特殊的内置变量,通常被 shell

脚本用来从命令行接受参数,或被函数用来保存传递给它的参数。

执行 shell 脚本时,用户可以通过命令行向脚本传递信息,跟在脚本名后面的用空格隔开的每个字符串都称为位置参量。 在脚本中使用这些参数时,需通过位置参量来引用。例如: $1 表示第一个参数, $2 表示第二个参数,以此类推。 $9 以后需要用花括号把数字括起来,如第 10 个位置参量以 ${10} 的方式来访问。

位置参量(命令行参数)

Page 46: Linux 环境中的程序设计基础

$0 当前脚本的文件名$1-$9 第 1 个到第 9 个位置参量${10} 第 10 个位置参量,类似地,有 ${11} , ...

$# 位置参量的个数$* 以单字符串显示所有位置参量$@ 未加双引号时与 $* 含义相同,加双引号时有区别$$ 脚本运行的当前进程号$! 最后一个后台运行的进程的进程号$? 显示前面最后一个命令的退出状态。

0 表示没有错误,其他任何值表示有错误。$- 显示当前 shell 使用的选项

位置参量列表

Page 47: Linux 环境中的程序设计基础

Shell 脚本

Shell 脚本的编写

shell 脚本

当命令不在命令行中执行,而是从一个文件中执行时,该文件就称为 shell 脚本,即按顺序执行的 Linux 命令集。 shell 脚本按行解释。

Shell 脚本是纯文本文件,可以使用任何文本编辑器编写 Shell 脚本通常是以 .sh 作为后缀名 Shell 脚本的执行chmod +x script_name

./script_name

sh script_name

Page 48: Linux 环境中的程序设计基础

条件测试

条件测试可以根据某个特定条件是否满足,来选择执行相应的任务。 Bash 中允许测试两种类型的条件: 命令成功或失败,表达式为真或假 任何一种测试中,都要有退出状态(返回值),退出状态为 0 表示命令成功或表达式为真,非 0 则表示命令失败或表达式为假。

Page 49: Linux 环境中的程序设计基础

内置测试命令 test 通常用 test 命令来测试表达式的值

x=5; y=10test $x -gt $yecho $?

test 命令可以用 方括号 来代替x=5; y=10[ $x -gt $y ] echo $?

表达式测试包括字符串测试、整数测试和文件测试。

测试表达式的值

方括号前后要留空格!

Page 50: Linux 环境中的程序设计基础

name=Tom [ $name = [Tt]?? ] echo $?

2.x 版本以上的 Bash 中可以用双方括号来测试表达式的值,此时可以使用通配符进行模式匹配。

测试表达式的值

[[ $name = [Tt]?? ]] echo $?

Page 51: Linux 环境中的程序设计基础

字符串测试[ -z str ] 如果字符串 str 长度为 0 ,返回真[ -n str ] 如果字符串 str 长度不为 0 ,返回

真[ str1 = str2 ] 两字符串相等[ str1 != str2 ] 两字符串不等

name=Tom; [ -z $name ]; echo $?

操作符两边必须留空格!

字符串测试

name2=Andy; [ $name = $name2 ] ; echo $?

Page 52: Linux 环境中的程序设计基础

整数测试,即比较大小[ int1 -eq int2 ] int1 等于 int2[ int1 -ne int2 ] int1 不等于 int2[ int1 -gt int2 ] int1 大于 int2[ int1 -ge int2 ] int1 大于或等于 int2[ int1 -lt int2 ] int1 小于 int2[ int1 -le int2 ] int1 小于或等于 int2

x=1; [ $x -eq 1 ]; echo $?

x=a; [ $x -eq 1 ]; echo $?

整数测试

操作符两边必须留空格!

X

Page 53: Linux 环境中的程序设计基础

整数测试也可以使用 let 命令或双圆括号

x=1; let "$x == 1"; echo $?

x=1; (($x+1>= 2 )); echo $?

只能用于整数测试!

整数测试

相应的操作符为:

== 、 != 、 > 、 >= 、 < 、 <=

例:

两种测试方法的区别 使用的操作符不同 let 和 双圆括号中可以使用算术表达式,而中括号不能 let 和 双圆括号中,操作符两边可以不留空格

Page 54: Linux 环境中的程序设计基础

逻辑测试[ expr1 -a expr2 ] 逻辑与,都为真时,结果为真[ expr1 -o expr2 ] 逻辑或,有一个为真时,结果为真

[ ! expr ] 逻辑非

x=1; name=Tom;

[ $x -eq 1 –a –n $name ]; echo $?

逻辑测试

注:不能随便添加括号

[ ( $x -eq 1 ) –a ( –n $name ) ]; echo $? X

Page 55: Linux 环境中的程序设计基础

x=1; name=Tom;

[[ $x -eq 1 && $name = To? ]]; echo $?

[[ pattern1 && pattern2 ]] 逻辑与

[[ pattern1 || pattern2 ]] 逻辑或

[[ ! pattern ]] 逻辑非

可以使用模式的逻辑测试

逻辑测试

Page 56: Linux 环境中的程序设计基础

文件测试:文件是否存在,文件属性,访问权限等。

-f fname fname 存在且是普通文件时,返回真 ( 即返回 0 )

-L fname fname 存在且是链接文件时,返回真 -d fname fname 存在且是一个目录时,返回真 -e fname fname (文件或目录)存在时,返回真 -s fname fname 存在且大小大于 0 时,返回真 -r fname fname (文件或目录)存在且可读时,返回真 -w fname fname (文件或目录)存在且可写时,返回真 -x fname fname (文件或目录)存在且可执行时,返回真

常见的文件测试操作符

更多文件测试符参见 test 的在线帮助

man test

文件测试

Page 57: Linux 环境中的程序设计基础

检查空值

[ "$name" = "" ]

[ ! "$name" ]

[ "X${name}" != "X" ]

检查空值

Page 58: Linux 环境中的程序设计基础

语法结构if expr1 # 如果 expr1 为真 (返回值为 0)then # 那么 commands1 # 执行语句块 commands1elif expr2 # 若 expr1 不真,而 expr2 为真then # 那么 commands2 # 执行语句块 commands2 ... ... # 可以有多个 elif 语句 else # else 最多只能有一个 commands4 # 执行语句块 commands4fi # if 语句必须以单词 fi 终止

if 条件语句

Page 59: Linux 环境中的程序设计基础

commands 为可执行语句块,如果为空,需使用 shell 提供的空命令 “ : ” ,即冒号。该命令不做任何事情,只返回一个退出状态 0 if 语句可以嵌套使用

ex4if.sh, chkperm.sh, chkperm2.sh, name_grep, tellme, tellme2, idcheck.sh

几点说明

elif 可以有任意多个( 0 个或多个) else 最多只能有一个( 0 个或 1 个) if 语句必须以 fi 表示结束 expr 通常为条件测试表达式;也可以是多个命令,以最后一个命令的退出状态为条件值。

Page 60: Linux 环境中的程序设计基础

语法结构case expr in # expr 为表达式,关键词 in 不要忘! pattern1) # 若 expr 与 pattern1 匹配,注意括号 commands1 # 执行语句块 commands1 ;; # 跳出 case 结构 pattern2) # 若 expr 与 pattern2 匹配 commands2 # 执行语句块 commands2 ;; # 跳出 case 结构 ... ... # 可以有任意多个模式匹配 *) # 若 expr 与上面的模式都不匹配 commands # 执行语句块 commands ;; # 跳出 case 结构esac # case 语句必须以 esac 终止

case 选择语句

Page 61: Linux 环境中的程序设计基础

case 语句举例: yes_no.sh

几点说明

每个命令块的最后必须有一个双分号,可以独占一行,或放在最后一个命令的后面。

所给的匹配模式 pattern 中可以含有通配符和“ | ” 。

如果 expr 没有找到匹配的模式,则执行缺省值 “ *) ” 后面的命令块 ( 类似于 if 中的 else ) ; “ *) ” 可以不出现。

表达式 expr 按顺序匹配每个模式,一旦有一个模式匹配成功,则执行该模式后面的所有命令,然后退出 case。

Page 62: Linux 环境中的程序设计基础

语法结构for variable in list # 每一次循环,依次把列表 list 中的一个值赋给循环变量do # 循环开始的标志 commands # 循环变量每取一次值,循环体就执行一遍done # 循环结束的标志

几点说明 列表 list 可以是命令替换、变量名替换、字符串和文件名列表 ( 可包含通配符 )

for 循环执行的次数取决于列表 list 中单词的个数 for 循环体中一般要出现循环变量,但也可以不出现

for 循环语句

Page 63: Linux 环境中的程序设计基础

执行第一轮循环时,将 list 中的第一个词赋给循环变量,并把该词从 list 中删除,然后进入循环体,执行 do 和 done 之间的命令。下一次进入循环体时,则将第二个词赋给循环变量,并把该词从 list 中删除,再往后的循环也以此类推。当 list 中的词全部被移走后,循环就结束了。

循环执行过程

forloop.sh, mybackup.sh

位置参量的使用: $* 与 $@ greet.sh

可以省略 in list ,此时使用位置参量permx.sh tellme greet.sh / permx.sh *

for 循环执行过程

Page 64: Linux 环境中的程序设计基础

语法结构while expr # 执行 exprdo # 若 expr 的退出状态为 0,进入循环,否则退出while commands # 循环体done # 循环结束标志,返回循环顶部

执行过程

先执行 expr ,如果其退出状态为 0 ,就执行循环体。执行到关键字 done 后,回到循环的顶部, while 命令再次检查 expr 的退出状态。以此类推,循环将一直继续下去,直到 expr 的退出状态非 0 为止。

while 循环语句

Page 65: Linux 环境中的程序设计基础

shift [n]

用于将参量列表 list 左移指定次数,缺省为左移一次。 参量列表 list 一旦被移动,最左端的那个参数就从列表中删除。 while 循环遍历位置参量列表时,常用到 shift。

doit.sh a b c d e f g h

shft.sh a b c d e f g h

循环控制 shift 命令

例:

Page 66: Linux 环境中的程序设计基础

条件判断命令 test

条件表达式是控制程序流程的关键, shell 提供的

test 命令适用于条件控制流和循环控制流

格式: test < 表达式 >

功能:返回表达式成立与否的状态值,

— 如果表达式成立,则 test 返回真的状态值 0 ,

— 反之, test 返回假的状态值,即一个非 0 值。

Page 67: Linux 环境中的程序设计基础

条件控制流

① if-then-else 结构 if < 条件判断命令>

then < 命令集 1>

else < 命令集 2>

fi 通常采用“ test < 表达式 >” ,当条件成立,则返回 0 ;条件不成立,则返回一个非 0 值 注意:其中 if 和 fi 必须配对出现

  ② if-then-fi 结构

if < 条件判断命令 >

then < 命令集 >

fi

Page 68: Linux 环境中的程序设计基础

例:如果 /etc 目录中的文件 profile 存在,则将其复制到 /home 中,并分屏显示 /home 下的 profile 内容;否则在屯幕上显示信息“ profile is not exist!”

if test -e /etc/profile then cp /etc/profile /home cat /etc/profile|more else echo “profile is not exist!”fi

Page 69: Linux 环境中的程序设计基础

建立程序文件 shp3 ,存放在当前目录下。如果shp3 运行时未带参数,则在屏幕上显示信息“ Parameter is lost!” , 并结束程序运行;如果 shp3 运行时带一个参数,则判断参数所指定的文件是否存在,如果存在则复制该文件到 /home ;否则先在屏幕上显示信息“ File not found!” ,然后显示程序本身。

Page 70: Linux 环境中的程序设计基础

if test -z $1 -z 判 $1存在否 then echo Parameter is lost! 如带一参数 else if test -e $1 则 $1 肯定在 then cp $1 /home else echo File not found! cat $0 $0 指程序本身 fifi

Page 71: Linux 环境中的程序设计基础

例:编写 shell 程序 shp6 ,存放在当前目录下。运行shp6 时带一个正真数参数,将数值存入变量 value ;如果该参数大于等于 1 但小于 3 ,则在屏幕上显示“ value is less than 3 and not less than 1”;如果该参数大于等于 3 ,则在屏幕上显示“ value is not less than 3”;最后以“ value=xx” 的形式显示变量 value 的值。

Page 72: Linux 环境中的程序设计基础

value=$1if test value -ge 1 -a value -lt 3 then echo value is less than 3 and not less than 1fiif test value -ge 3 then echo value is not less than 3fiecho value=$value

Page 73: Linux 环境中的程序设计基础

例:编 1 个 shell 程序 shp10 ,当以命令“ shp10 xx yy” 执行时,(其中 xx 为年份参数, yy 为季度参数),能自动清屏,并显示指定年份指定季度中的 3 个月的月历。

Page 74: Linux 环境中的程序设计基础

cleark=$2if test $k -eq 1 then cal 1 $1 cal 2 $1 cal 3 $1fiif test $k -eq 2 then cal 4 $1 cal 5 $1 cal 6 $1fi

if test $k -eq 3 then cal 7 $1 cal 8 $1 cal 9 $1fiif test $k -eq 4 then cal 10 $1 cal 11 $1 cal 12 $1fi

Page 75: Linux 环境中的程序设计基础

③ case 结构case < 变量 > in

字符串 1) < 命令集 1>

;;

字符串 n) < 命令集 n>

;;

*) < 缺省命令 >

;;

esac

说明:其中,字符串中可含通配符。如果能同时匹配多个字符串,则只能执行第一个匹配字

符串后的 < 命令集 > 。

Page 76: Linux 环境中的程序设计基础

循环控制流

① for-in 结构

for < 循环变量 > [in < 循环变量取值集 >]

do

< 命令集 >

done

  其中, < 循环变量取值集 > 中的值与值之间用空格分

隔。

Page 77: Linux 环境中的程序设计基础

例:用 for 命令实现,在当前目录下创建名为user0 、 user1 、… user9 十个子目录,用长格式显示这 10 个目录的目录信息,然后用 for 命令删去这 10个目录后,再用长格式显示这 10 个目录的目录信息。 for i in 0 1 2 3 4 5 6 7 8 9 do mkdir user$i done ls -dl user?|more for i in 0 1 2 3 4 5 6 7 8 9 do rm -rf user$i done ls -dl user?|more

Page 78: Linux 环境中的程序设计基础

例: (1) 清屏(2) 当程序运行时,屏幕显示如下形式信息:***********************This is a shell program ***********************(3) 检查 /home 目录下,是否存在由参数 1 指定的文件,若不存在,则屏幕显示信息“ File not found!” ;若存在,则将参数 1 指定的文件改名为由参数 2 指定的文件名,然后用 for 命令对改名后的文件显示其长格式的目录信息和文件内容

Page 79: Linux 环境中的程序设计基础

clearecho “**********************”echo “*This is a shell program *”echo “ **********************”

Page 80: Linux 环境中的程序设计基础

if test -n $1 -a -n $2 then if test $1!=$2 then if test -e $1 then mv $1 $2 for cn in “ls -l” “cat” do $cn $2 echo “” done          else echo File not found! fi     fifi

Page 81: Linux 环境中的程序设计基础

② while 结构 while < 条件判断命令 >

do

< 命令集 >

done

说明:当 < 条件判断命令 > 返回 0 时,则执行一轮由do 和 done 括起来的循环体中的 < 命令集 > ,直到 <条件判断命令 > 返回一个非 0 值时,则不再执行循环体中的命令,执行 done 后面的命令

Page 82: Linux 环境中的程序设计基础

③ until 结构 until <条件判断命令 >

do

< 命令集>

done

执行过程说明:与 while 结构相反,当 < 条件判断命令 > 返回非0 时,执行循环体中的命令,直到 < 条件判断命令 > 返回一个 0 值时,继续执行 done 后面的命令。

Page 83: Linux 环境中的程序设计基础

shell 程序的调试

有两种简便的跟踪功能可以用于 shell 程序的调试

格式 1 : set -v

功能:当执行一个 shell 程序时,会在执行程序文件中的每条命令之前,自动在屏幕上先显示该条命令

格式 2 : set -x

功能:当执行 shell 程序时,它会把将要执行的命令逐条进行参量定值,并以最后执行的形式在屏幕上显示

Page 84: Linux 环境中的程序设计基础

Linux 环境中的程序设计基础

Linux编程环境

Page 85: Linux 环境中的程序设计基础

Linux C/C++ 编程C 语言是一种在 Unix 操作系统中被广泛使用的通用编程语言。用 C 语言写的程序执行速度很快。C 语言非常适合编写系统程序, Linux 内核就是使用 C 语言编写的。ANSI C 的 C 语言标准

目标是为各种操作系统上的 C 程序提供可移植性保证,而不仅仅限于 Unix 。

不仅定义了 C 编程语言的语法和语义,还定义了一个标准库。

Page 86: Linux 环境中的程序设计基础

标准库可以根据头文件划分为 15 个部分,其中包括字符类型 <ctype.h> 、错误码<errno.h> 、浮点常数 <float.h> 、数学常数 <math.h> 、标准定义 <stddef.h> 、标准 I/O<stdio.h> 、工具函数<stdlib.h> 、字符串操作 <string.h> 、时间和日期 <time.h> 、可变参数表<stdarg.h> 、信号 <signal.h> 、非局部跳转 <setjmp.h> 、本地信息<local.h> 及程序断言 <assert.h> 等。

Page 87: Linux 环境中的程序设计基础

C 语言开发环境简介Linux 上广泛使用的 C 语言编译器是 GNU C 编译器, GNU C 建立在自由软件基金会的编程许可证的基础上,可以自由发布。在 Linux 下,一个完整的 C 语言开发环境到少包括以下三个组成部分:

函数库 glibc 编译器 gcc 系统头文件 glibc_header

glibc 是构成一个完整的 C 语言开发环境所必不可少的组成部分,也是 Linux 下 C 语言的主要函数库。glibc_header 中包含了系统编译源代码所需要的声明文件 ,如果缺少系统头文件,很多用到系统功能的 C 程序将无法编译。

Page 88: Linux 环境中的程序设计基础

glibc 有两种安装方式: 安装成测试用的函数库在编译程序时用不同的选项来试用新的函数库。 安装成主要的 C 语言函数库所有新编译程序均使用的函数库。

gcc 是可以在多种硬件平台上编译出可执行程序的超级编译器, gcc 编译器能将 C 语言、 C++语言源程序、汇编语言程序和目标程序编译、连接成可执行文件。在 Linux 系统中,可执行文件没有统一的后缀,系统从文件的属性来区分可执行文件和不可执行文件。而 gcc 则通过后缀来区别输入文件的类型。

Page 89: Linux 环境中的程序设计基础

gcc支持编译的一些源文件的后缀及其说明:

后缀名 说明.c C 语言源代码文件.a 由目标文件构成的档案库文件

.C/.cc/.cxx C++源代码文件.h 程序所包含的头文件.i 已经预处理过的 C 语言源代码文件.ii 已经预处理过的 C++源代码文件.m Objective-C 语言源代码文件.o 编译后的目标文件.s 汇编语言源代码文件.S 经过预编译的汇编语言源代码文件

Page 90: Linux 环境中的程序设计基础

在 Linux 中, gcc ( GNU C Compiler )是C 、 C++ 、 Objective-C源程序的编译器, gcc 编译C源程序并生成可执行文件要经过以下四步:

( 1 )预处理gcc 编译器调用 cpp 程序,对各种命令如

#define 、 #include 进行分析。( 2 )编译gcc 编译器调用 ccl 程序,根据输入文件产生中间文件。( 3 )汇编gcc 编译器调用 as 程序,用中间文件作为输入产生

以 .o 作为类型名的目标文件。( 4 )连接gcc 编译器调用 ld 程序,将各目标程序组合于可执行文

件中的适当位置,这一程序引用的函数也放在可执行文件中。

Page 91: Linux 环境中的程序设计基础

C 函数库定义:是一些预先编译好的函数的集合,那些函数都是按照可再使用的原则编写的。它们通常是一组相互关联的用来完成某项常见工作的函数构成(比如 c 库里面的标准输入输出函数、时间函数和数学函数等)。函数库中的函数可以通过连接程序与应用程序进行连接,而不必在每次开发程序时都对这些通用的函数进行编译。不同类型的应用程序将会使用不同的函数库。如数学应用将使用数学库 libm , X-Window 应用程序将使用 Xlib 库及 libX11 。

Page 92: Linux 环境中的程序设计基础

所有的程序都将使用标准的 C 函数库 -libc ,该库中包含了内存管理或输入输出操作的基本函数,这些库都存放在 /usr/lib 这些系统公用的目录中,系统中的任何用户都可以利用这些库。库可以有三种使用的形式:

静态库:代码在编译时就已连接到开发人员开发的应用程序中。

共享库:只是在程序开始运行时才载入,在编译时,只是简单地指定需要使用的库函数。

动态库:是共享库的另一种变化形式,也是在程序运行时载入,使用的库函数不是在程序运行开始,而是在程序中的语句需要使用该函数时才载入。

Page 93: Linux 环境中的程序设计基础

动态库可以在程序运行期间释放动态库所占用的内存,腾出空间供其他程序使用。由于共享库和动态库并没有在程序中包括库函数的内容,只是包含了对库函数的引用,因此代码的规模比较小。已经开始的大多数库都采用共享库的方式。 ELF 格式的可执行文件使得共享库能够比较容易地实现,当然使用旧的 a.out 模式也可以实现库的共享。 Linux 系统中目前可执行文件的标准格式为 ELF 格式。

Page 94: Linux 环境中的程序设计基础

系统中可用的库都存放在 /usr/lib 和 /lib目录中。库文件名由前缀 lib 和库名以及后缀组成。根据库的类型不同,后缀名也不一样。共享库的后缀名由 .so和版本号组成,静态库名的后缀名为 .a 或 .sa (采用旧的 a.out 格式的共享库)。

共享库名的格式:库的名称 .so.主版本号 .次版本号

静态库名的格式:库的名称 .a例如:libm.so.5 数学共享库的标识字符为m,版本号为 5

libm.a 静态数字库

Page 95: Linux 环境中的程序设计基础

库文件与头文件的位置函数库存放的标准目录:/lib 系统必备共享库/usr/lib 标准共享库和静态库/usr/i486-linux-libc5/lib libc5兼容性函数库/usr/X11R6/lib X11R6 的函数库/usr/local/lib 本地函数库头文件存放的目录:/usr/include 系统头文件/usr/local/include 本地头文件共享库及相关配置文件在 /etc 目录中,其中:ld.so.conf 包含共享库的搜索位置ldconfig 共享库管理工具,一般在更新了共享库之

后要运行该命令ldd 可查看可执行文件所使用的共享库

Page 96: Linux 环境中的程序设计基础

gcc 的基本用法和选项

格式: gcc [options] [filename]…

常用选项的说明:-ansi 只支持 ANSI 标准的 C 语法。这一选项将禁止 GNU

C 的某些特色, 例如 asm 或 typeof 关键词。 -c 对源程序进行预处理、编译,产生目标文件,但不进行

连接成为可执行文件。-DMACRO 以字符串“ 1” 定义 MACRO 宏。

-DMACRO=DEFN 以字符串“ DEFN” 定义

MACRO 宏。 -E 在预处理后停止,输出预处理后的源代码至标准输出,

不进行编译。

Page 97: Linux 环境中的程序设计基础

-g 产生一张用于调试和排错的扩展符号表,此选项使程序可用 gdb 进行调试。

-o < 文件名 > 定义输出的执行文件名为 < 文件名 >

-S 在编译后停止,产生类型名为 s 的汇编代码文件,不生成中间文件。

-O 对程序编译进行优化,减少被编译程序的长度和执行时间,但此时的编译速度比不作优化慢且要求较多的内存。

-lobjc 可用于连接类型名为 o的目标文件生成可执行文件。

-w 不生成任何警告信息-Wall生成所有警告信息。

Page 98: Linux 环境中的程序设计基础

/* 程序清单 main.c*/ #include <stdio.h> #include <stdlib.h>int factorial (int n); int main (int argc, char **argv) {

int n; if (argc < 2) {

printf ("Usage: %s n\n", argv [0]); return -1;

} else {

n = atoi (argv[1]); printf ("Factorial of %d is %d.\n", n, factorial (n));

}return 0;

}

假设有 两个源文件 main.c 和 factorial.c ,现在要编译生成一个计算阶乘的程序。

/* 程序清单 factorial.c*/#include <stdio.h>#include <stdlib.h> int factorial (int n) {

if (n <= 1) return 1;

else return

factorial (n - 1) * n; } $ gcc -o factorial main.c factorial.c

$ ./factorial 5

Factorial of 5 is 120.

Page 99: Linux 环境中的程序设计基础

GCC 可同时用来编译 C 程序和 C++ 程序。一般来说,C 编译器通过源文件的后缀名来判断是 C 程序还是 C+ + 程序。在 Linux 中, C 源文件的后缀名为 .c ,而 C++ 源文件的后缀名为 .C 或 .cpp 。 但是, gcc 命令只能编译 C++ 源文件,而不能自动和 C++ 程序使用的库连接。因此,通常使用 g++ 命令来完成 C++ 程序的编译和连接,该程序会自动调用 gcc 实现编译。 假设我们有一个如下的 C++ 源文件( hello.C ): #include <iostream.h>void main (void) {

cout << "Hello, world!" << endl; }

$ g++ -o hello hello.C

$ ./hello

Hello, world!

Page 100: Linux 环境中的程序设计基础

调试 C 程序当编译后得到的目标程序在运行时出现故障时,需要对你的源程序进行调试以找出错误,排除故障。Linux 提供了调试源程序的工具 gdb ( GNU debugger )。GNU 的调试器称为 gdb ,该程序是一个交互式工具,工作在字符模式。在 X Window 系统中,有一个 gdb 的 前端图形工具,称为 xxgdb 。gdb 是功能强大的调试程序,可完成如下的调试任务:

设置断点; 监视程序变量的值; 程序的单步执行; 修改变量的值。

Page 101: Linux 环境中的程序设计基础

gdb 不仅允许用户在运行程序时显示源代码,而且在调试过程中允许在预设的断点处暂停程序的运行,显示变量的内容。在可以使用 gdb 调试程序之前,必须使用 -g 选项编译源文件。可在 makefile 中如下定义 CFLAGS 变量:

CFLAGS = -g运行 gdb 调试程序时通常使用如下的命令:

#gdb progname

Page 102: Linux 环境中的程序设计基础

在 gdb 提示符处键入 help ,将列出命令的分类,主要的分类有: aliases :命令别名 breakpoints :断点定义 data :数据查看 files :指定并查看文件 internals :维护命令 running :程序执行 stack :调用栈查看 statu :状态查看 tracepoints :跟踪程序执行

键入 help 后跟命令的分类名,可获得该类命令的详细清单。

Page 103: Linux 环境中的程序设计基础

gdb 的常用命令 break NUM 在指定的行上设置断点。bt 显示所有的调用栈帧。该命令可用来显示函数的调用顺序clear 删除设置在特定源文件、特定行上的断点。其用法为:

clear FILENAME:NUM

continue 继续执行正在调试的程序。该命令用在程序由于处理信号或断点而导致停止运行时

display EXPR 每次程序停止后显示表达式的值。表达式由程序定义的变量组成

file FILE 装载指定的可执行文件进行调试help NAME 显示指定命令的帮助信息quit 退出 gdb 。也可以输入 'C-d' 来退出 gdb

run 执行载入后的要调试的程序。可以输入参数set 修改变量值。格式如下: set varible=value

step 单步执行,进入遇到的函数next 单步执行,不进入函数调用,即视函数调用为普通语句

Page 104: Linux 环境中的程序设计基础

info break 显示当前断点清单,包括到达断点处的次数等info files 显示被调试文件的详细信息info func 显示所有的函数名称info local 显示当函数中的局部变量信息info prog 显示被调试程序的执行状态info var 显示所有的全局和静态变量名称kill 终止正被调试的程序list 显示源代码段make 在不退出 gdb 的情况下运行 make 工具next 在不单步执行进入其他函数的情况下,向前执行一行源代码print EXPR 显示表达式 EXPR 的值

注意:在使用 gdb 调试程序前,必须使用 gcc –g 对源程序进行编译。

Page 105: Linux 环境中的程序设计基础

建立C源程序文件 star.c ,输出结果如下**********程序内容如下:#include <stdio.h>int main(){

int i=10 ; do

{printf (“ *” );++i ;

}while ( i<10 ); printf (“ \n” ); }} 编译程序 star.c ,其目标程序以 star 命名且可用 gdb 进行调试

Page 106: Linux 环境中的程序设计基础

#gcc -o star -g star.c或#gcc -g star.c -o star#./star*为了查找该程序中的逻辑错误,使用 gdb 进行调试:#gdb ./starGNU gdb Red Hat Linux………(gdb)run*(gdb)whereNo stack

Page 107: Linux 环境中的程序设计基础

(gdb)list1 #include <stdio.h>2 int main()3 {4 int i=10 ;5 do6 {7 printf (“ *” );8 ++i ;9 }while ( i<10 );10 printf (“ \n” );(gdb)break 1Breakpoint 1 at 0x8048370:file star.c,line 1.(gdb)runBreakpoint 1,main() at star.c:33 {

Page 108: Linux 环境中的程序设计基础

(gdb)step7 printf(“*”);(gdb)print i$1=7146752可见 i的值为随机数,出错在于变量 i在 gdb 中,可以直接修改变量的值,为此在第 4 行处设置断点(gdb)clear 1Deleted breakpoint 1(gdb)break 4Breakpoint 2 at 0x8048380:file star.c,line 4.

Page 109: Linux 环境中的程序设计基础

(gdb)runThe program being debugged has been started already.Start it from the beginning?(y or n) yStarting program:/root/starBreakpoint 2,main() at star.c:44 int i=10;(gdb)step7 printf(“*”);(gdb)print i$2=10(gdb)set var i=0(gdb)print i$3=0(gdb)continue**********