第1篇 Linux下C语言基础 2
第1章 Linux简介(?教学视频:16分钟) 2
1.1 GNU简介 2
1.2 Linux简介 2
1.2.1 Linux发展史 2
1.2.2 Linux发行版 4
1.2.3 Linux内核版本 5
1.2.4 Linux与UNIX的关系 5
1.2.5 Linux在服务器方面的发展 5
1.2.6 Linux在嵌入式系统方面的发展 6
1.2.7 Linux在桌面系统方面的发展 6
1.3 Linux环境下的其他编程语言 7
1.3.1 C++++ 7
1.3.2 Java 9
1.3.3 Perl 11
1.3.4 Python 12
1.3.5 Ruby 13
1.3.6 PHP 13
第2章 控制结构(?教学视频:56分钟) 16
2.1 goto语句 16
2.1.1 C语言中的无条件跳转 16
2.1.2 使用goto语句进行出错处理 17
2.1.3 出错处理的一般模型 19
2.2 C语言中的分支结构 20
2.2.1 分支结构的翻译 20
2.2.2 使用goto语句实现分支结构 22
2.3 短路计算 22
2.3.1 短路计算 22
2.3.2 &&运算的短路计算 23
2.3.3 Ⅱ运算的短路计算 24
2.4 C语言中的循环结构 26
2.4.1 while循环 26
2.4.2 do…while循环 28
2.4.3 for循环 30
2.5 switch语句 32
2.5.1 switch语句的应用 32
2.5.2 使用goto语句实现switch语句 33
2.6 优化控制结构 34
2.6.1 表达式优化——使用替换程序中的乘除法 34
2.6.2 表达式优化——常量折叠 35
2.6.3 表达式优化——使用数学公式 36
2.6.4 表达式优化——存储问题 37
2.6.5 分支优化——改变判断顺序 38
2.6.6 分支优化——使用switch语句 41
2.6.7 循环优化——次性计算 42
第3章 C语言中的函数(?教学视频:56分钟) 46
3.1 函数的本质 46
3.2 变量的作用域和生命期 47
3.2.1 全局变量 47
3.2.2 局部变量 48
3.3 变量的初始值 50
3.3.1 全局变量的初始值 50
3.3.2 局部变量的初始值 50
3.4 与函数有关的优化 51
3.4.1 函数调用与程序优化 52
3.4.2 变量存储优化 54
3.5 编写多文件程序——变量的存储类别 56
3.5.1 存储类别 56
3.5.2 static变量的作用——改变变量的生命期 56
3.5.3 static变量的作用——实现封装和模块化设计 58
3.6 编写多文件的程序——链接的作用 61
3.6.1 链接多个文件 61
3.6.2 链接时符号解析规则 63
3.6.3 链接规则的应用 63
3.7 可变参数 66
3.7.1 可变参数的概念 66
3.7.2 实现一个简单的可变参数的函数 67
3.7.3 可变参数实例 69
3.7.4 关于printf()函数的疑问——缺少整型参数 74
3.7.5 关于printf()函数的疑问——缺少字符串地址参数 75
第4章 C语言中的指针与字符串(?教学视频:48分钟) 78
4.1 sizeof运算符 78
4.1.1 sizeof运算符的应用——得到内置类型的大小 78
4.1.2 sizeof运算符的应用——得到复合类型的大小 79
4.2 指针的应用 80
4.2.1 指针与别名陷阱 80
4.2.2 数组的指针 82
4.2.3 指针的指针 83
4.2.4 指针与参数传递 85
4.2.5 指针类型的意义 90
4.2.6 void型指针 91
4.3 函数的指针 94
4.3.1 C语言中的函数指针 94
4.3.2 函数指针的应用——回调函数 97
4.3.3 函数指针数组 102
4.4 字符串 103
4.4.1 字符串与字符数组 103
4.4.2 字符串与指针 104
4.4.3 限定修饰符const 106
4.4.4 const关键字修饰指针——在指针定义之前 107
4.4.5 const关键字修饰指针——在指针定义之中 107
4.4.6 const关键字修饰指针——在指针定义之前和定义之中 107
4.4.7 使用const关键字的意义 108
第5章 C语言的高级技术(?教学视频:30分钟) 111
5.1 结构体与共同体 111
5.1.1 结构体中成员变量的存储分布 111
5.1.2 内存对齐 112
5.2 位运算 115
5.2.1 掩码运算 115
5.2.2 不安全的位运算 117
5.2.3 异或运算的特性 119
5.2.4 移位运算的陷阱 121
5.2.5 移位运算的实例 122
5.3 预处理 124
5.3.1 常用的代码组织形式 124
5.3.2 调试开关 129
5.4 C99新标准关键字详解 130
5.4.1 inline关键字的概念 131
5.4.2 inline关键字实例 131
5.4.3 inline关键字使用总结 132
5.4.4 restrict关键字的概念 133
5.4.5 restrict关键字的应用 134
第2篇 C语言开发环境 136
第6章 vi编辑器(?教学视频:44分钟) 136
6.1 vi编辑器入门 136
6.1.1 vi简介 136
6.1.2 vi的工作模式 136
6.2 vi一般操作 137
6.2.1 进入vi 137
6.2.2 文本插入操作 140
6.2.3 文本删除操作 141
6.2.4 文本复制操作 143
6.2.5 撤销命令 144
6.2.6 重复命令 145
6.2.7 退出vi 145
6.3 vi的增强操作 147
6.3.1 替换命令 147
6.3.2 光标移动 148
6.3.3 按行移动光标 148
6.3.4 按字移动光标 149
6.3.5 按句移动光标 150
6.3.6 按段移动光标 151
6.3.7 文本行的移动 151
6.3.8 文本的异行移动 153
6.3.9 屏幕滚动 153
6.3.10 查找命令 154
6.3.11 替换命令 155
6.3.12 窗口的切分 157
6.3.13 设置环境 157
第7章 gcc编译器(?教学视频:27分钟) 159
7.1 初探gcc编译器 159
7.1.1 从经典的hello world开始 159
7.1.2 gcc编译流程 160
7.2 gcc常用选项 160
7.2.1 gcc常用选项汇总 161
7.2.2 -c选项 161
7.2.3 -S选项 162
7.2.4 -E选项 163
7.2.5 -o选项 164
7.2.6 -I选项 165
7.2.7 -g选项 165
7.3 链接原理 165
7.3.1 链接器的任务 165
7.3.2 目标文件 165
7.3.3 ELF格式的可重定位目标文件 167
7.3.4 目标文件中的符号表 168
7.3.5 重定位的概念 172
7.3.6 符号的重定位信息 172
7.4 关于库 173
7.4.1 使用库的优势 173
7.4.2 静态库的概念 175
7.4.3 创建静态库 175
7.4.4 使用静态库 176
7.4.5 动态库的概念 177
7.4.6 创建动态库 178
7.4.7 使用动态库 180
7.5 gcc工具链 181
第8章 构建makefile文件(?教学视频:46分钟) 183
8.1 makefile文件入门 183
8.1.1 makefile文件的组成内容 183
8.1.2 makefile文件包含 183
8.1.3 make工具的退出码 184
8.2 书写makefile规则 185
8.2.1 使用基本规则 185
8.2.2 使用隐式规则 186
8.2.3 使用伪目标 187
8.2.4 使用通配符 188
8.2.5 搜索源文件 189
8.3 使用命令 190
8.3.1 显示命令 190
8.3.2 执行命令 190
8.3.3 命令出错 192
8.4 使用变量 192
8.4.1 使用普通变量 192
8.4.2 变量中的变量 194
8.4.3 追加变量的值 196
8.4.4 自动化变量 197
8.5 使用条件判断 197
8.5.1 条件表达式 197
8.5.2 表达式实例 199
8.6 使用函数 200
8.6.1 函数调用的语法 200
8.6.2 字符串处理函数 201
8.6.3 文件名操作函数 206
8.6.4 foreach函数 209
8.6.5 if函数 210
8.6.6 call函数 210
8.6.7 origin函数 211
8.6.8 shell函数 211
8.7 makefile实例 212
8.7.1 makefile实例——项目中的总makefile 212
8.7.2 makefile实例makefile模板 214
第9章 gdb调试器(?教学视频:27分钟) 216
9.1 列出源程序 216
9.1.1 不带参数的list命令 216
9.1.2 带一个参数的list命令 217
9.1.3 带两个参数的list命令 217
9.2 运行程序的命令 218
9.3 操作断点的命令 220
9.3.1 设置断点 220
9.3.2 显示当前gdb的断点信息 222
9.3.3 删除指定的断点 223
9.3.4 禁止或启用断点 223
9.3.5 清除断点 223
9.3.6 观察点 224
9.3.7 设置断点实例 225
9.4 查看运行时数据 228
9.4.1 数据观察命令 229
9.4.2 对程序中函数的调用 230
9.4.3 查看表达式的值 231
9.4.4 查看数组的值 231
9.4.5 变量的输出格式 232
9.4.6 查看内存 233
9.4.7 自动显示变量 233
9.4.8 设置显示选项 237
9.4.9 显示变量的历史记录 239
9.4.10 查看寄存器 239
9.4.11 查看使用gdb环境变量 240
9.4.12 查看数据实例 241
9.5 改变程序的执行 245
9.5.1 修改变量的值 246
9.5.2 跳转执行 246
9.5.3 信号的产生及处理 248
9.5.4 强制调用函数 248
9.5.5 强制函数返回 249
9.6 gdb高级应用 249
9.6.1 产生core文件 250
9.6.2 跟踪栈上数据 250
9.6.3 绑定运行进程 252
9.6.4 源文件搜索 254
9.6.5 机器语言工具 254
9.6.6 其他有用的调试命令 255
第3篇 Linux进程操作 258
第10章 进程环境(?教学视频:44分钟) 258
10.1 程序的启动和退出 258
10.1.1 在shell中启动一个程序 258
10.1.2 加载一个程序 259
10.1.3 加载地址 260
10.1.4 退出程序 261
10.1.5 进程终止处理函数 262
10.2 Linux进程内存管理 263
10.2.1 数据的内部存储 263
10.2.2 C程序的存储布局——代码段 265
10.2.3 C程序的存储布局——数据段和缓冲段 267
10.2.4 C程序的存储布局——栈 268
10.2.5 C程序的存储布局——堆 269
10.2.6 常量的存储 270
10.2.7 动态内存管理 271
10.2.8 动态内存分配的深入研究 273
10.3 shell环境 276
10.3.1 命令行参数 277
10.3.2 得到程序文件名 278
10.3.3 环境变量 278
10.3.4 得到指定的环境变量 280
10.3.5 设置一个环境变量 280
10.3.6 得到进程结束状态 285
10.3.7 使用ermo调试程序 286
10.3.8 输出错误原因 288
10.4 全局跳转 289
10.4.1 局部跳转的局限性 289
10.4.2 使用全局跳转 291
10.4.3 使用全局跳转代替局部跳转 292
第11章 进程控制(?教学视频:45分钟) 295
11.1 进程标识符 295
11.1.1 进程ID 295
11.1.2 进程中重要的ID值 296
11.2 进程操作 297
11.2.1 创建一个进程 298
11.2.2 父子进程的共享资源 299
11.2.3 fork()函数的出错情况 302
11.2.4 创建一个共享空间的子进程 303
11.2.5 在函数内部调用vfork()函数 304
11.2.6 退出进程 305
11.2.7 使用exit() 函数检查进程出错信息 306
11.2.8 exit()函数与内核函数的关系 307
11.2.9 设置进程所有者 307
11.2.10 调试多进程——设置跟踪流 309
11.2.11 调试多进程——使用gdb的attach命令 309
11.3 执行程序 310
11.3.1 执行一个新程序 310
11.3.2 执行解释器文件 313
11.3.3 在程序中执行shell命令 315
11.3.4 实现system()函数 317
11.4 关系操作 318
11.4.1 等待进程退出 318
11.4.2 等待指定的进程 321
11.4.3 僵尸进程的概念 323
11.4.4 产生一个僵尸进程 324
11.4.5 避免僵尸进程的产生 325
11.4.6 输出进程统计信息 327
第12章 时间和日历历程(?教学视频:7分钟) 330
12.1 系统时间 330
12.2 日历时间 332
第13章 信号及信号处理(?教学视频:48分钟) 335
13.1 信号的基础 335
13.1.1 信号的基本概念 335
13.1.2 产生信号 336
13.1.3 处理信号 336
13.1.4 常用信号的使用方法 337
13.2 信号的影响 338
13.2.1 重入 339
13.2.2 原子操作 341
13.2.3 中断系统调用 343
13.3 信号处理函数 343
13.3.1 设置信号处理函数 343
13.3.2 发送信号 347
13.3.3 向进程本身发送信号 348
13.3.4 设置Linux定时器 349
13.3.5 定时等待I/O 350
13.3.6 挂起进程 352
13.3.7 进程休眠 353
13.4 信号集与屏蔽信号 356
13.4.1 信号集和信号集处理函数 356
13.4.2 屏蔽信号 358
13.4.3 处理未决信号 360
13.4.4 高级信号注册函数 362
13.4.5 信号选项实例——SA NOCLDWAIT选项 363
13.4.6 信号选项实例——SA NODEFER选项 364
13.4.7 信号选项实例——SA RESETHAND选项 366
第14章 进程间通信(?教学视频:52分钟) 368
14.1 进程间通信概述 368
14.1.1 进程间通信简介 368
14.1.2 进程间通信的难点 369
14.1.3 IPC的多种方式 369
14.2 管道 370
14.2.1 管道的概念 370
14.2.2 匿名半双工管道 370
14.2.3 匿名半双工管道的读写操作 371
14.2.4 创建管道的标准库函数 375
14.3 FIFO管道 377
14.3.1 FIFO的概念 377
14.3.2 创建FIFO 378
14.3.3 FIFO的读写操作 379
14.3.4 FIFO的缺点 382
14.4 System V IPC/POSIX IPC 383
14.4.1 IPC对象的概念 383
14.4.2 IPC对象的问题 385
14.4.3 IPC对象系统命令 385
14.5 共享内存 386
14.5.1 共享内存的概念 386
14.5.2 共享内存的创建 387
14.5.3 共享内存的操作 388
14.5.4 共享内存使用注意事项 390
14.6 信号量 391
14.6.1 信号量的概念 391
14.6.2 信号量的创建 392
14.6.3 信号量集的操作 394
14.7 消息队列 396
14.7.1 消息队列的概念 396
14.7.2 创建消息队列 397
14.7.3 读写消息队列 399
第15章 线程(?教学视频:34分钟 403
15.1 线程与进程 403
15.1.1 线程的概念 403
15.1.2 线程的优势 404
15.2 线程标识符 405
15.3 线程基本操作 405
15.3.1 创建线程 405
15.3.2 向线程体函数传递参数 407
15.3.3 线程访问资源的限制 409
15.3.4 终止线程 412
15.3.5 正确得到线程退出信息的方法 415
15.3.6 取消一个线程的运行 417
15.3.7 线程退出函数 420
第16章 线程高级操作(?教学视频:28分钟) 423
16.1 线程同步——使用互斥量 423
16.1.1 初始化与销毁互斥量 423
16.1.2 得到与释放互斥量 424
16.1.3 使用互斥量的实例 425
16.2 线程同步——使用读写锁 430
16.2.1 初始化与销毁读写锁 430
16.2.2 得到与释放互斥锁 431
16.2.3 使用互斥量与读写锁的比较 432
16.3 线程属性 438
16.3.1 创建和销毁属性结构 438
16.3.2 线程的分离状态 439
16.3.3 分离一个已经创建的线程 440
16.3.4 线程栈的属性 442
第4篇 Linux文件操作 446
第17章 文件I/O(?教学视频:71分钟) 446
17.1 文件描述符的概念 446
17.2 文件I/O操作 446
17.2.1 打开一个文件 446
17.2.2 打开文件的出错情况 450
17.2.3 关闭一个文件 450
17.2.4 创建一个新文件 451
17.2.5 文件定位 453
17.2.6 文件截短 455
17.2.7 清空一个文件 458
17.2.8 文件的读写操作 460
17.2.9 文件同步 463
17.3 文件描述符操作 465
17.3.1 复制文件描述符 465
17.3.2 I/O重定向概念及其应用 466
17.3.3 控制文件 469
17.3.4 修改打开文件的文件状态 470
17.4 非阻塞文件I/O 473
17.4.1 非阻塞I/O的概念 473
17.4.2 以非阻塞方式打开文件 474
17.4.3 将一个打开文件设置为非阻塞方式 475
17.5 内存映射I/O 477
17.5.1 内存映射I/O的概念 477
17.5.2 创建一个内存映射 478
17.5.3 撤销一个内存映射 480
17.5.4 内存映射同步 482
17.5.5 更改内存映射的权限 485
第18章 文件管理(?教学视频:42分钟 487
18.1 文件状态 487
18.2 文件类型 488
18.3 文件权限 490
18.3.1 访问权限 491
18.3.2 设置用户ID位和设置组ID位 492
18.3.3 设置用户ID位的作用 493
18.3.4 使用设置用户ID位的实例 494
18.4 文件权限操作 496
18.4.1 测试文件访问权限 497
18.4.2 设置用户ID位与文件权限测试 499
18.4.3 使用文件权限屏蔽字 499
18.4.4 在shell中使用文件权限屏蔽字 500
18.4.5 在程序中使用文件权限屏蔽字 501
18.4.6 改变文件访问权限 502
18.4.7 在shell中改变文件权限 503
18.4.8 在程序中改变文件权限 504
18.4.9 改变一个打开的文件权限 505
18.5 文件系统结构 509
18.6 文件的硬链接 513
18.6.1 创建一个硬链接 513
18.6.2 删除一个硬链接 515
18.7 改变文件所有者 519
18.8 操作文件的时间 522
第19章 目录操作(?教学视频:30分钟) 526
19.1 目录的权限 526
19.1.1 目录的访问权限 526
19.1.2 测试目录的访问权限 527
19.2 目录操作 528
19.2.1 创建一个目录 528
19.2.2 删除一个目录 529
19.2.3 目录项结构 530
19.2.4 打开与关闭目录 531
19.2.5 读目录 531
19.2.6 读目录操作的实例——实现自己的Is命令 534
19.2.7 得到目录文件的读写位置 536
19.2.8 定位目录 537
19.2.9 回卷目录文件 539
19.3 进程的工作目录 540
19.3.1 工作目录的概念 540
19.3.2 改变进程的工作目录 541
19.3.3 得到进程的当前工作目录 542
19.3.4 子进程工作目录对父进程的影响 545
第20章 特殊文件(?教学视频:32分钟) 548
20.1 符号链接操作 548
20.1.1 符号链接 548
20.1.2 符号链接的功能 549
20.1.3 创建符号链接 549
20.1.4 创建指向不存在文件的符号链接 550
20.1.5 读写符号链接的目的文件 551
20.1.6 读写多重符号链接的目的文件 553
20.1.7 读写符号链接 555
20.1.8 取得符号链接的状态 558
20.1.9 更改符号链接的所有者 562
20.2 proc文件系统 566
20.2.1 proc文件系统 566
20.2.2 常用的内核信息 567
20.2.3 读取内核信息 568
20.2.4 进程状态信息 575
20.2.5 读取进程状态 576
20.2.6 proc文件系统编程实例——实现自己的ps命令 578
第21章 基于流的I/O(?教学视频:30分钟) 581
21.1 流与缓冲 581
21.2 基于流的文件操作 583
21.2.1 打开和关闭流 583
21.2.2 文件内容的冲洗 585
21.2.3 以字符为单位读写数据 587
21.2.4 以行为单位读写数据 588
21.2.5 gets()函数的漏洞 589
21.2.6 逐行读取文件内容 590
21.2.7 输出XML形式的配置文件 591
21.2.8 读写数据块 593
21.2.9 文件读写实例——实现cp命令 594
21.2.10 文件读写实例——字符统计 596
21.2.11 文件读写实例——目录下所有文件的字符统计 597
第5篇 Linux网络编程 602
第22章 TCP和UDP协议(?教学视频:22分钟) 602
22.1 计算机网络的体系结构简介 602
22.1.1 计算机网络体系结构简介 602
22.1.2 OSI参考模型中各层功能描述 603
22.1.3 TCP/IP参考模型的各层功能描述 603
22.1.4 面向连接服务和无连接服务 604
22.2 客户/服务器方式简介 604
22.3 用户数据报协议UDP 605
22.3.1 用户数据报的格式 605
22.3.2 用户数据报检验和的计算 606
22.3.3 UDP用户数据报的特性及用途 607
22.4 传输控制协议TCP 608
22.4.1 TCP简介 608
22.4.2 TCP报文段的首部 608
22.4.3 TCP数据编号与确认 609
22.4.4 TCP的流量控制与拥塞控制 610
22.4.5 TCP的运输连接管理 612
第23章 网络编程基础(?教学视频: 50分钟) 614
23.1 套接字概念 614
23.2 准备工作 615
23.2.1 字节序 615
23.2.2 地址格式 616
23.2.3 地址形式转换 617
23.2.4 获得主机信息 619
23.2.5 地址映射 620
23.3 套接字基础编程 621
23.3.1 建立和销毁套接字描述符 621
23.3.2 地址绑定 623
23.3.3 建立一个连接 624
23.3.4 最简单的网络应用程序——服务器端 626
23.3.5 最简单的网络应用程序——客户端 629
23.3.6 使用文件读写函数读写套接字 631
23.3.7 使用完整读写函数的网络应用程序 634
23.3.8 面向连接的数据传输 637
23.3.9 面向连接的网络应用程序——服务器端 638
23.3.10 面向连接的网络应用程序——客户端 641
23.3.11 无连接的数据传输 643
23.3.12 无连接的网络应用程序——服务器端 644
23.3.13 无连接的网络应用程序——客户端 646
23.4 非阻塞套接字 649
23.4.1 非阻塞网络应用程序——服务器端 649
23.4.2 非阻塞网络应用程序——客户端 651
第24章 网络编程进阶(?教学视频:32分钟) 654
24.1 套接字编程深入 654
24.1.1 bind函数的作用 654
24.1.2 并发服务器 655
24.1.3 UDP协议的connect()函数应用 657
24.2 多路选择I/O 660
24.2.1 多路选择I/O的概念 660
24.2.2 实现多路选择I/O 661
24.2.3 使用多路选择I/O处理多个连接 663
24.2.4 屏蔽信号的多路选择I/O 666
24.2.5 对比select()函数和pselect() 函数 667
24.2.6 轮询I/O 669
24.3 非网络通信套接字 670
24.3.1 非命名UNIX域套接字 671
24.3.2 命名UNIX域套接字 672
24.3.3 UNIX域套接字实例——服务器端 673
24.3.4 UNIX域套接字实例——客户端 677
第25章 网络编程实例——实现文件传输程序(?教学视频:18分钟) 679
25.1 程序设计 679
25.1.1 整体程序设计 679
25.1.2 客户端程序设计 679
25.1.3 服务器端程序设计 680
25.2 文件传输程序的实现 683
25.2.1 客户端程序的实现——头文件 683
25.2.2 客户端程序的实现——程序主函数 684
25.2.3 客户端程序的实现——命令拆分函数 686
25.2.4 客户端程序的实现——命令处理模块 687
25.2.5 服务器端程序的实现——头文件 697
25.2.6 服务器端程序的实现——程序主函数 698
25.2.7 服务器端程序的实现——客户端命令处理模块 699
25.3 测试和验证 706
第26章 网络编程实例——简单的Web服务器(?教学视频:10分钟) 707
26.1 程序设计 707
26.1.1 整体程序设计 707
26.1.2 步骤1——解析客户端发送的内容 708
26.1.3 步骤2——寻找客户端需要的文件 709
26.1.4 步骤3——将客户端信息返回 709
26.2 Web服务器的实现 710
26.2.1 Web服务器程序的实现——头文件 710
26.2.2 Web服务器程序的实现——程序主函数 711
26.2.3 Web服务器程序的实现——请求处理模块 715
26.3 测试和验证 719
第6篇 shell脚本知识 722
第27章 shell脚本基础(?教学视频:32分钟) 722
27.1 编写最简单的shell脚本 722
27.1.1 使用shell脚本的原因 722
27.1.2 脚本内容 723
27.1.3 运行一段脚本 724
27.2 shell中的变量 724
27.2.1 用户自定义变量 725
27.2.2 引用变量 726
27.2.3 为表达式求值 727
27.2.4 变量的类型 729
27.2.5 操作自定义变量 730
27.2.6 位置变量 731
27.2.7 重新分配位置变量 732
27.3 退出状态 734
27.4 条件测试 736
27.4.1 测试文件状态 736
27.4.2 测试时使用逻辑操作符 738
27.4.3 字符串测试 739
27.4.4 测试数值 741
第28章 shell脚本中的控制结构(?教学视频:29分钟) 743
28.1 shell脚本中的命令替换 743
28.2 分支结构 744
28.2.1 if/else分支结构 744
28.2.2 多重分支结构 745
28.2.3 使用case结构的分支语句 747
28.2.4 在case语句中使用逻辑表达式 749
28.3 条件测试命令的值 750
28.3.1 测试整数与字符串 751
28.3.2 测试字符串和空值 752
28.3.3 测试未初始化的变量 752
28.3.4 测试“false”的值 753
28.4 循环结构 754
28.4.1 while循环结构 754
28.4.2 until循环结构 757
28.4.3 for循环结构 759
28.4.4 break和continue命令 762
28.5 定义函数和使用函数 764