高级 Bash 脚本编程指南

对 Shell 脚本艺术的深入探讨

门德尔·库珀

4.2.01

2006 年 12 月 15 日

修订历史
修订版 4.02006 年 6 月 18 日修订人:mc
'WINTERBERRY' 版本:重大更新。
修订版 4.12006 年 10 月 8 日修订人:mc
'WAXBERRY' 版本:次要更新。
修订版 4.22006 年 12 月 10 日修订人:mc
'SPARKLEBERRY' 版本:重要更新。

本教程假定您没有脚本或编程的先前知识,但会迅速进展到中级/高级水平的教学。 . . 同时偷偷地介绍一些 UNIX® 的智慧和传说。它既是一本教科书,又是自学手册,也是 Shell 脚本技术的参考和知识来源。练习和大量注释的示例邀请读者积极参与,其前提是真正学习脚本的唯一方法就是编写脚本.

本书适合作为课堂上学习编程概念的通用介绍。

此文档的最新更新,作为一个归档的,bzip2 压缩“tarball”,包括 SGML 源代码和渲染后的 HTML,可以从作者的主页下载。 也可以下载 pdf 版本。 请参阅 更改日志 以获取修订历史记录。


献词

献给安妮塔,所有魔力的源泉

目录
第一部分。简介
1. 为什么选择 Shell 编程?
2. 从 Sha-Bang 开始
第二部分。基础
3. 特殊字符
4. 变量和参数简介
5. 引用
6. 退出和退出状态
7. 测试
8. 运算及相关主题
第三部分。超越基础
9. 变量重访
10. 循环和分支
11. 命令替换
12. 算术扩展
13. 休息时间
第四部分。命令
14. 内部命令和内置命令
15. 外部过滤器、程序和命令
16. 系统和管理命令
第五部分。高级主题
17. 正则表达式
18. Here Documents
19. I/O 重定向
20. 子 Shell
21. 受限 Shell
22. 进程替换
23. 函数
24. 别名
25. 列表结构
26. 数组
27. /dev/proc
28. 关于零和空值
29. 调试
30. 选项
31. 陷阱
32. 风格化的脚本编写
33. 杂项
34. Bash,版本 2 和 3
35. 尾注
35.1. 作者注
35.2. 关于作者
35.3. 获取帮助的地方
35.4. 用于制作本书的工具
35.5. 鸣谢
参考文献
A. 贡献的脚本
B. 参考卡片
C. Sed 和 Awk 微型入门
C.1. Sed
C.2. Awk
D. 具有特殊含义的退出代码
E. I/O 和 I/O 重定向的详细介绍
F. 命令行选项
F.1. 标准命令行选项
F.2. Bash 命令行选项
G. 重要文件
H. 重要系统目录
I. 本地化
J. 历史命令
K. 一个示例 .bashrc 文件
L. 将 DOS 批处理文件转换为 Shell 脚本
M. 练习
M.1. 分析脚本
M.2. 编写脚本
N. 修订历史
O. 镜像站点
P. 待办事项列表
Q. 版权
表格列表
14-1. 作业标识符
30-1. Bash 选项
33-1. 转义序列中表示颜色的数字
B-1. 特殊 Shell 变量
B-2. TEST 运算符:二进制比较
B-3. TEST 运算符:文件
B-4. 参数替换和扩展
B-5. 字符串操作
B-6. 杂项结构
C-1. 基本的 sed 运算符
C-2. sed 运算符示例
D-1. 具有特殊含义的保留退出代码
L-1. 批处理文件关键字/变量/运算符及其 Shell 等效项
L-2. DOS 命令及其 UNIX 等效项
N-1. 修订历史
示例列表
2-1. cleanup:清理 /var/log 中的日志文件的脚本
2-2. cleanup:改进的清理脚本
2-3. cleanup:上述脚本的增强型通用版本。
3-1. 代码块和 I/O 重定向
3-2. 将代码块的结果保存到文件
3-3. 在后台运行循环
3-4. 备份过去一天内更改的所有文件
4-1. 变量赋值和替换
4-2. 纯变量赋值
4-3. 变量赋值,纯粹而花哨
4-4. 整数还是字符串?
4-5. 位置参数
4-6. whwhois 域名查找
4-7. 使用 shift
5-1. 回显奇怪的变量
5-2. 转义字符
6-1. exit / 退出状态
6-2. 使用 ! 取消条件
7-1. 什么是真?
7-2. test/usr/bin/test[ ]/usr/bin/[ 的等效性
7-3. 使用 (( )) 进行算术测试
7-4. 测试损坏的链接
7-5. 算术和字符串比较
7-6. 测试字符串是否为null
7-7. zmore
8-1. 最大公约数
8-2. 使用算术运算
8-3. 使用 && 和 || 进行复合条件测试
8-4. 数值常数的表示
9-1. $IFS 和空格
9-2. 定时输入
9-3. 再次,定时输入
9-4. 定时 read
9-5. 我是 root 吗?
9-6. arglist:使用 $* 和 $@ 列出参数
9-7. $* 和 $@ 的不一致行为
9-8. $* 和 $@ 在 $IFS 为空时
9-9. 下划线变量
9-10. 在文本文件中段落之间插入一个空行
9-11. 转换图形文件格式,并更改文件名
9-12. 将流式音频文件转换为ogg
9-13. 模拟 getopt
9-14. 提取子字符串的替代方法
9-15. 使用参数替换和错误消息
9-16. 参数替换和“usage”消息
9-17. 变量的长度
9-18. 参数替换中的模式匹配
9-19. 重命名文件扩展名:
9-20. 使用模式匹配解析任意字符串
9-21. 匹配字符串的前缀或后缀模式
9-22. 使用 declare 对变量进行类型化
9-23. 间接引用
9-24. 将间接引用传递给 awk
9-25. 生成随机数
9-26. 从一副牌中抽取一张随机牌
9-27. 在值之间随机
9-28. 使用 RANDOM 掷一个骰子
9-29. 重新播种 RANDOM
9-30. 伪随机数,使用 awk
9-31. C 类型变量操作
10-1. 简单的 for 循环
10-2. for 循环,每个 [list] 元素有两个参数
10-3. Fileinfo: 操作包含在变量中的文件列表
10-4. 使用 for 循环操作文件
10-5. for 循环中缺少 in [list]
10-6. 使用命令替换在 for 循环中生成 [list]
10-7. 用于二进制文件的 grep 替代方案
10-8. 列出系统上的所有用户
10-9. 检查目录中的所有二进制文件以确定作者
10-10. 列出目录中的 符号链接
10-11. 目录中的符号链接,保存到文件
10-12. 类似 C 的 for 循环
10-13. 批量模式下使用 efax
10-14. 简单的 while 循环
10-15. 另一个 while 循环
10-16. while 循环具有多个条件
10-17. while 循环中使用类似 C 的语法
10-18. until 循环
10-19. 嵌套循环
10-20. 循环中 breakcontinue 的影响
10-21. 跳出多个循环级别
10-22. 在更高的循环级别继续
10-23. 在实际任务中使用 continue N
10-24. 使用 case
10-25. 使用 case 创建菜单
10-26. 使用 命令替换 生成 case 变量
10-27. 简单的字符串匹配
10-28. 检查字母输入
10-29. 使用 select 创建菜单
10-30. 在函数中使用 select 创建菜单
11-1. 愚蠢的脚本技巧
11-2. 从循环生成变量
11-3. 查找字谜
14-1. 一个分叉自身多个实例的脚本
14-2. printf 实际操作
14-3. 使用 read 进行变量赋值
14-4. read 没有变量时会发生什么
14-5. 多行输入到 read
14-6. 检测箭头键
14-7. 使用 read文件重定向
14-8. 从管道读取时的问题
14-9. 更改当前工作目录
14-10. let 执行算术运算。
14-11. 显示 eval 的效果
14-12. 回显 命令行参数
14-13. 强制注销
14-14. rot13 的一个版本
14-15. 使用 eval 强制在 Perl 脚本中进行变量替换
14-16. 使用 set 与位置参数
14-17. 反转位置参数
14-18. 重新分配位置参数
14-19. “取消设置” 变量
14-20. 使用 export 将变量传递给嵌入的 awk 脚本
14-21. 使用 getopts 读取传递给脚本的选项/参数
14-22. “包含” 数据文件
14-23. 一个引用自身的脚本
14-24. exec 的影响
14-25. 一个 exec's 自身的脚本
14-26. 在继续之前等待进程完成
14-27. 一个杀死自身的脚本
15-1. 使用 ls 创建用于刻录 CDR 光盘的内容表
15-2. 你好或再见
15-3. Badname,消除当前目录中包含坏字符和 空白字符的文件名。
15-4. 通过其 inode 号删除文件
15-5. Logfile:使用 xargs 监视系统日志
15-6. 将当前目录中的文件复制到另一个目录
15-7. 按名称杀死进程
15-8. 使用 xargs 进行词频分析
15-9. 使用 expr
15-10. 使用 date
15-11. 词频分析
15-12. 哪些文件是脚本?
15-13. 生成 10 位随机数
15-14. 使用 tail 监视系统日志
15-15. 在脚本中模拟 grep
15-16. 在韦伯斯特 1913 词典中查找定义
15-17. 检查列表中单词的有效性
15-18. toupper:将文件转换为全部大写。
15-19. lowercase:将工作目录中的所有文件名更改为小写。
15-20. du:DOS 到 UNIX 文本文件转换。
15-21. rot13:超弱加密。
15-22. 生成 “Crypto-Quote” 谜题
15-23. 格式化的文件列表。
15-24. 使用 column 格式化目录列表
15-25. nl:一个自动编号脚本。
15-26. manview:查看格式化的 man 页面
15-27. 使用 cpio 移动目录树
15-28. 解包 rpm 归档文件
15-29. 从 C 程序文件中删除注释
15-30. 探索 /usr/X11R6/bin
15-31. 一个 “改进的” strings 命令
15-32. 使用 cmp 在脚本中比较两个文件。
15-33. basenamedirname
15-34. 检查文件完整性
15-35. Uudecoding 编码文件
15-36. 查找报告垃圾邮件发送者的位置
15-37. 分析垃圾邮件域名
15-38. 获取股票报价
15-39. 更新 FC4
15-40. 使用 ssh
15-41. 一个给自己发送邮件的脚本
15-42. 房贷月供
15-43. 进制转换
15-44. 使用 here document 调用 bc
15-45. 计算 PI
15-46. 将十进制数转换为十六进制
15-47. 因式分解
15-48. 计算直角三角形的斜边
15-49. 使用 seq 生成循环参数
15-50. 字母计数
15-51. 使用 getopt 解析命令行选项
15-52. 一个复制自身的脚本
15-53. 练习 dd
15-54. 捕获按键
15-55. 安全删除文件
15-56. 文件名生成器
15-57. 将米转换为英里
15-58. 使用 m4
16-1. 设置新密码
16-2. 设置 erase 字符
16-3. secret password:关闭终端回显
16-4. 按键检测
16-5. 检查远程服务器是否具有 identd
16-6. pidof 有助于杀死进程
16-7. 检查 CD 镜像
16-8. 在文件中创建文件系统
16-9. 添加新的硬盘
16-10. 使用 umask 隐藏输出文件,防止窥视
16-11. killall,来自 /etc/rc.d/init.d
18-1. broadcast:向所有登录用户发送消息
18-2. dummyfile:创建一个 2 行的虚拟文件
18-3. 使用 cat 发送多行消息
18-4. 多行消息,抑制制表符
18-5. 具有参数替换的 here document
18-6. 将文件对上传到 Sunsite incoming 目录
18-7. 关闭参数替换
18-8. 生成另一个脚本的脚本
18-9. Here documents 和函数
18-10. “匿名” Here Document
18-11. 注释掉代码块
18-12. 一个自文档脚本
18-13. 将一行添加到文件的前面
18-14. 解析邮箱
19-1. 使用 exec 重定向 stdin
19-2. 使用 exec 重定向 stdout
19-3. 在同一个脚本中使用 exec 重定向 stdinstdout
19-4. 避免子 shell
19-5. 重定向的 while 循环
19-6. 重定向的 while 循环的另一种形式
19-7. 重定向的 until 循环
19-8. 重定向的 for 循环
19-9. 重定向的 for 循环(同时重定向 stdinstdout
19-10. 重定向 if/then 测试
19-11. 用于上述示例的数据文件 names.data
19-12. 记录事件
20-1. 子shell 中的变量作用域
20-2. 列出用户配置文件
20-3. 在子shell 中并行运行进程
21-1. 以受限模式运行脚本
23-1. 简单函数
23-2. 接受参数的函数
23-3. 函数和传递给脚本的命令行参数
23-4. 将间接引用传递给函数
23-5. 解引用传递给函数的参数
23-6. 再次,解引用传递给函数的参数
23-7. 两个数的最大值
23-8. 将数字转换为罗马数字
23-9. 在函数中测试大的返回值
23-10. 比较两个大整数
23-11. 从用户名获取真实姓名
23-12. 局部变量可见性
23-13. 递归,使用局部变量
23-14. 汉诺塔
24-1. 脚本中的别名
24-2. unalias:设置和取消别名
25-1. 使用 and 列表测试命令行参数
25-2. 使用 and 列表的另一个命令行参数测试
25-3. or 列表and 列表结合使用
26-1. 简单的数组用法
26-2. 格式化一首诗
26-3. 各种数组操作
26-4. 数组上的字符串操作
26-5. 将脚本的内容加载到数组中
26-6. 数组的一些特殊属性
26-7. 关于空数组和空元素
26-8. 初始化数组
26-9. 复制和连接数组
26-10. 更多关于连接数组
26-11. 冒泡排序
26-12. 嵌入式数组和间接引用
26-13. 复杂的数组应用:埃拉托斯特尼筛法
26-14. 模拟一个压栈
26-15. 复杂的数组应用:探索一个奇怪的数学级数
26-16. 模拟二维数组,然后倾斜它
27-1. 使用 /dev/tcp 进行故障排除
27-2. 查找与 PID 关联的进程
27-3. 在线连接状态
28-1. 隐藏饼干罐
28-2. 使用 /dev/zero 设置交换文件
28-3. 创建一个内存盘
29-1. 一个有 bug 的脚本
29-2. 缺少 关键字
29-3. test24:另一个有 bug 的脚本
29-4. 使用 assert 测试条件
29-5. 在退出时捕获
29-6. 清理 Control-C 之后
29-7. 跟踪一个变量
29-8. 运行多个进程(在 SMP 机器上)
31-1. 数值和字符串比较不相等
31-2. 子shell 陷阱
31-3. echo 的输出通过管道传递给 read
33-1. shell 包装器
33-2. 一个更复杂的 shell 包装器
33-3. 一个通用的 shell 包装器,写入日志文件
33-4. 一个围绕 awk 脚本的 shell 包装器
33-5. 一个围绕另一个 awk 脚本的 shell 包装器
33-6. Perl 嵌入在 Bash 脚本中
33-7. Bash 和 Perl 脚本组合
33-8. 一个(无用)递归调用自身的脚本
33-9. 一个(有用)递归调用自身的脚本
33-10. 另一个(有用)递归调用自身的脚本
33-11. 一个“彩色”地址数据库
33-12. 绘制一个框
33-13. 回显彩色文本
33-14. 一个“赛马”游戏
33-15. 返回值技巧
33-16. 更多返回值技巧
33-17. 传递和返回数组
33-18. 玩转字谜
33-19. 从 shell 脚本调用的小部件
34-1. 字符串扩展
34-2. 间接变量引用 - 新方法
34-3. 简单的数据库应用程序,使用间接变量引用
34-4. 使用数组和其他杂项技巧从一副牌中发四张随机牌
A-1. mailformat:格式化电子邮件消息
A-2. rn:一个简单的文件重命名实用程序
A-3. blank-rename:重命名包含空格的文件名
A-4. encryptedpw:使用本地加密密码上传到 ftp 站点
A-5. copy-cd:复制数据 CD
A-6. 考拉兹序列
A-7. days-between:计算两个日期之间的天数
A-8. 制作一个“字典”
A-9. Soundex 转换
A-10. “生命游戏”
A-11. “生命游戏”的数据文件
A-12. behead:删除邮件和新闻消息头
A-13. ftpget:通过 ftp 下载文件
A-14. password:生成随机 8 位密码
A-15. fifo:使用命名管道进行每日备份
A-16. 使用模运算符生成质数
A-17. tree:显示目录树
A-18. string 函数:类似 C 的字符串函数
A-19. 目录信息
A-20. 面向对象数据库
A-21. 哈希函数库
A-22. 使用哈希函数对文本进行着色
A-23. 更多关于哈希函数
A-24. 挂载 USB 密钥存储设备
A-25. 保存网络日志
A-26. 保护字面字符串
A-27. 取消保护字面字符串
A-28. 垃圾邮件识别
A-29. 垃圾邮件猎人
A-30. 使 wget 更易于使用
A-31. 一个“播客”脚本
A-32. 每日备份到 firewire HD
A-33. 一个扩展的 cd 命令
A-34. 基础回顾
C-1. 统计字母出现次数
K-1. 示例 .bashrc 文件
L-1. VIEWDATA.BAT:DOS 批处理文件
L-2. viewdata.sh:VIEWDATA.BAT 的 Shell 脚本转换
P-1. 打印服务器环境