个人工具

高级Bash脚本编程指南

来自Ubuntu中文

跳转至: 导航, 搜索

转载说明

譯者序

毫無疑問,UNIX/Linux最重要的軟件之一就是shell,目前最流行的shell被稱為Bash(Bourne Again Shell),幾乎所有的Linux和絕大部分的UNIX都可以使用Bash。作為系統與用戶之間的交互接口,shell幾乎是你在UNIX工作平台上最親密的朋友,因此,學好shell,是學習Linux/UNIX的的開始,並且它會始終伴隨你的工作學習。

shell是如此地重要,但令人驚奇的是,介紹shell的書沒有真正令人滿意的。所幸的是,我看到了這本被人稱為abs的書,這本書介紹了bash大量的細節和廣闊的範圍,我遇到的絕大部分的技術問題--無論是我忘記的或是以前沒有發現的--都可以在這本書裡找到答案。這本使用大量的例子詳細地介紹了Bash的語法,各種技巧,調試等等的技術,以循序漸進的學習方式,讓你瞭解Bash的所有特性,在書中還有許多練習可以引導你思考,以得到更深入的知識。無論你是新手還是老手,或是使用其他語言的程序員,我能肯定你能在此書用受益。而本書除了介紹BASH的知識之外,也有許多有用的關於Linux/UNIX的知識和其他shell的介紹。

在看到本書的英文版後,我決定把它翻譯出來,在Linuxsir論壇上結識了譯者之一楊春敏共同翻譯這本書,600多頁的書是本大部頭的書,我們花了6個月的業餘時間才翻譯完了。

關於版權的問題,英文版的作者Mendel Cooper對英文版的版權做了詳細的約定,請參考:Appendix Q. Copyright。中文版版權由譯者楊春敏和黃毅共同所有,在遵守英文版版權相應條款的條件下,歡迎在保留本書譯者名字和版權說明以非盈利的方式自由發佈此中文版,以盈利目的的所有行為必須聯繫英文作者和兩位中文譯者以獲得許可。

本書得以成稿,我(黃毅)要多謝我的女朋友,本該給予她的時間我用來了翻譯,多謝你的理解,你是一個很棒的女朋友!

譯者 楊春敏 黃毅

2006.5.15

Advanced Bash-Scripting Guide

<<高級Bash腳本編程指南>>

一本深入學習shell腳本藝術的書籍

Version 3.7.2

2005/11/16

作者:Mendel Cooper

mail:[email protected]

這本書假定你沒有任何腳本或一般程序的編程知識,但是如果你有相關的知識,那麼你將很容易 達到中高級的水平...all the while sneaking in little snippets of UNIX? wisdom and lore(這句不知道怎麼譯).你可以把本書作為教材,自學手冊,或者你獲得shell腳本技術的文檔. 書中的練習和例子腳本中的註釋將會與讀者有更好的互動,但是最關鍵的前提是: 想真正學習腳本編程的唯一途徑就是編寫腳本.

這本書也可作為教材來講解一般的編程概念.

下載本書最新版本,這是一個以tar和bzip2進行打包的,並且是以HTML來發行的.http://personal.riverusers.com/~thegrendel/abs-guide-5.5.tar.bz2

當然,你也可以獲得本書的pdf版本在 http://www.tldp.org/LDP/abs/ http://mirrors.oss.org.cn/ebook/Shell/%B8%DF%BC%B6Bash%BD%C5%B1%BE%B1%E0%B3%CC%D6%B8%C4%CF.pdf

可以查看修訂歷史.http://personal.riverusers.com/~thegrendel/Change.log

譯者:楊春敏,黃毅

mail:[email protected]

一直想好好學習一下bash,可惜網上的資料都雜亂不堪,我還是喜歡通過一本書系統的學習.這本 書來得正是時候.本書的作者真是非常的嚴謹,從例子裡的改進人名單就能看出來.可惜我水平真 的是非常有限,好多地方估計譯得都有問題.希望閱讀的朋友們多多提些修改建議.我會盡我的最 大努力去修正它.

目录

第一部分. 热身

  1. 为什么使用shell编程
  2. 带着一个Sha-Bang出发(Sha-Bang指的是#!)
    1. 调用一个脚本
    2. 初步的练习

第二部分. 基本

  1. 特殊字符
  2. 变量和参数的介绍
    1. 变量替换
    2. 变量赋值
    3. Bash变量是不分类型的
    4. 特殊的变量类型
  3. 引用(翻译的可能有问题,特指引号)
    1. 引用变量
    2. 转义(\)
  4. 退出和退出状态
  5. Tests
    1. Test结构
    2. 文件测试操作
    3. 其他比较操作
    4. 嵌套的if/then条件test
    5. 检查你的test知识
  6. 操作符和相关的主题
    1. 操作符
    2. 数字常量

第三部分. 超越基本

  1. 变量重游
    1. 内部变量
    2. 操作字符串
    3. 参数替换
    4. 指定类型的变量:declare或者typeset
    5. 变量的间接引用
    6. RANDOM: 产生随机整数
    7. 双圆括号结构
  2. 循环和分支
    1. 循环
    2. 嵌套循环
    3. 循环控制
    4. 测试与分支(case和select结构)
  3. 内部命令与内建
    1. 作业控制命令
  4. 外部过滤器,程序和命令
    1. 基本命令
    2. 复杂命令
    3. 时间/日期 命令
    4. 文本处理命令
    5. 文件与归档命令
    6. 通讯命令
    7. 终端控制命令
    8. 数学计算命令
    9. 混杂命令
  5. 系统与管理命令
    1. 分析一个系统脚本
  6. 命令替换
  7. 算术扩展
  8. I/O 重定向
    1. 使用exec
    2. 代码块的重定向
    3. 应用
  9. Here Documents
    1. Here Strings
  10. 休息时间

第四部份. 高级

  1. 正则表达式
    1. 一个简要的正则表达式介绍
    2. 通配
  2. 子shell(Subshells)
  3. 受限shell(Restricted Shells)
  4. 进程替换
  5. 函数
    1. 复杂函数和函数复杂性
    2. 局部变量
    3. 不使用局部变量的递归
  6. 别名(Aliases)
  7. 列表结构
  8. 数组
  9. /dev 和 /proc
    1. /dev
    2. /proc
  10. 关于Zeros和Nulls
  11. 调试
  12. 选项
  13. Gotchas
  14. 脚本编程风格
    1. 非官方的Shell脚本风格
  15. 杂项
    1. 交互式和非交互式的shells和脚本
    2. Shell 包装
    3. 测试和比较: 另一种方法
    4. 递归
    5. 彩色脚本
    6. 优化
    7. 各种小技巧
    8. 安全话题
      1. 被感染的脚本
      2. 隐藏Shell脚本源码
    9. 移植话题
    10. 在Windows下进行Shell编程
  16. Bash, 版本 2 和 3
    1. Bash, 版本2
    2. Bash, 版本3

35. 后记

  1. 作者后记
  2. 关于作者
  3. 哪里可以取得帮助?
  4. 制作这本书的工具
    1. 硬件
    2. 软件和排版软件
  5. Credits

12344

表格清单

11-1. 作业标识符 30-1. Bash 选项 33-1. 转义序列中数值和彩色的对应 B-1. Special Shell Variables B-2. TEST Operators: Binary Comparison B-3. TEST Operators: Files B-4. Parameter Substitution and Expansion B-5. String Operations B-6. Miscellaneous Constructs C-1. Basic sed operators C-2. Examples of sed operators D-1. "Reserved" Exit Codes L-1. Batch file keywords / variables / operators, and their shell equivalents L-2. DOS commands and their UNIX equivalents N-1. Revision History

例子清单

2-1. 清除:清除/var/log下的log文件

2-2. 清除:一个改良的清除脚本

2-3. cleanup:一个增强的和广义的删除logfile的脚本

3-1. 代码块和I/O重定向

3-2. 将一个代码块的结果保存到文件

3-3. 在后台运行一个循环

3-4. 备份最后一天所有修改的文件.

4-1. 变量赋值和替换

4-2. 一般的变量赋值

4-3. 变量赋值,一般的和比较特殊的

4-4. 整型还是string?

4-5. 位置参数

4-6. wh,whois节点名字查询

4-7. 使用shift

5-1. echo一些诡异的变量

5-2. 转义符

6-1. exit/exit状态

6-2. 否定一个条件使用!

7-1. 什么情况下为真?

7-2. 几个等效命令test,/usr/bin/test,[],和/usr/bin/[

7-3. 算数测试使用(( ))

7-4. test死的链接文件

7-5. 数字和字符串比较

7-6. 测试字符串是否为null

7-7. zmore

8-1. 最大公约数

8-2. 使用算术操作符

8-3. 使用&&和||进行混合状态的test

8-4. 数字常量的处理

9-1. $IFS和空白

9-2. 时间输入

9-3. 再来一个时间输入

9-4. Timed read

9-5. 我是root?

9-6. arglist:通过$*和[email protected]列出所有的参数

9-7. 不一致的$*和[email protected]行为

9-8. 当$IFS为空时的$*和[email protected]

9-9. 下划线变量

9-10. 在一个文本文件的段间插入空行

9-11. 利用修改文件名,来转换图片格式

9-12. 模仿getopt命令

9-13. 提取字符串的一种可选的方法

9-14. 使用参数替换和error messages

9-15. 参数替换和"usage"messages

9-16. 变量长度

9-17. 参数替换中的模式匹配

9-18. 重命名文件扩展名

9-19. 使用模式匹配来分析比较特殊的字符串

9-20. 对字符串的前缀或后缀使用匹配模式

9-21. 使用declare来指定变量的类型

9-22. 间接引用

9-23. 传递一个间接引用给awk

9-24. 产生随机数

9-25. 从一副扑克牌中取出一张随机的牌

9-26. 两个指定值之间的随机数

9-27. 使用随机数来摇一个骰子

9-28. 重新分配随机数种子

9-29. 使用awk产生伪随机数

9-30. C风格的变量处理

10-1. 循环的一个简单例子

10-2. 每个[list]元素带两个参数的for循环

10-3. 文件信息:对包含在变量中的文件列表进行操作

10-4. 在for循环中操作文件

10-5. 在for循环中省略[list]

10-6. 使用命令替换来产生for循环的[list]

10-7. 对于二进制文件的一个grep替换

10-8. 列出系统上的所有用户

10-9. 在目录的所有文件中查找源字串

10-10. 列出目录中所有的符号连接文件

10-11. 将目录中的符号连接文件名保存到一个文件中

10-12. 一个C风格的for循环

10-13. 在batch mode中使用efax

10-14. 简单的while循环

10-15. 另一个while循环

10-16. 多条件的while循环

10-17. C风格的while循环

10-18. until循环

10-19. 嵌套循环

10-20. break和continue命令在循环中的效果

10-21. 多层循环的退出

10-22. 多层循环的continue

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. 一个fork出多个自己实例的脚本

11-2. printf

11-3. 使用read,变量分配

11-4. 当使用一个不带变量参数的read命令时,将会发生什么?

11-5. read命令的多行输入

11-6. 检测方向键

11-7. 通过文件重定向来使用read

11-8. 管道输出到read中的问题

11-9. 修改当前的工作目录

11-10. 用"let"命令来作算术操作.

11-11. 显示eval命令的效果

11-12. 强制登出(log-off)

11-13. 另一个"rot13"的版本

11-14. 在Perl脚本中使用eval命令来强制变量替换

11-15. 使用set来改变脚本的位置参数

11-16. 重新分配位置参数

11-17. Unset一个变量

11-18. 使用export命令传递一个变量到一个内嵌awk的脚本中

11-19. 使用getopts命令来读取传递给脚本的选项/参数.

11-20. "Including"一个数据文件

11-21. 一个没什么用的,source自身的脚本

11-22. exec的效果

11-23. 一个exec自身的脚本

11-24. 在继续处理之前,等待一个进程的结束

11-25. 一个结束自身的脚本.

12-1. 使用ls命令来创建一个烧录CDR的内容列表

12-2. Hello or Good-bye

12-3. 删除当前目录下文件名中包含一些特殊字符(包括空白)的文件..

12-4. 通过文件的 inode 号来删除文件

12-5. Logfile: 使用 xargs 来监控系统 log

12-6. 把当前目录下的文件拷贝到另一个文件中

12-7. 通过名字Kill进程

12-8. 使用xargs分析单词出现的频率

12-9. 使用 expr

12-10. 使用 date 命令

12-11. 分析单词出现的频率

12-12. 那个文件是脚本?

12-13. 产生10进制随机数

12-14. 使用 tail 命令来监控系统log

12-15. 在一个脚本中模仿 "grep" 的行为

12-16. 在1913年的韦氏词典中查找定义

12-17. 检查列表中单词的正确性

12-18. 转换大写: 把一个文件的内容全部转换为大写.

12-19. 转换小写: 将当前目录下的所有文全部转换为小写.

12-20. Du: DOS 到 UNIX 文本文件的转换.

12-21. rot13: rot13, 弱智加密.

12-22. Generating "Crypto-Quote" Puzzles

12-23. 格式化文件列表.

12-24. 使用 column 来格式化目录列表

12-25. nl: 一个自己计算行号的脚本.

12-26. manview: 查看格式化的man页

12-27. 使用 cpio 来拷贝一个目录树

12-28. 解包一个 rpm 归档文件

12-29. 从 C 文件中去掉注释

12-30. Exploring /usr/X11R6/bin

12-31. 一个"改进过"的 strings 命令

12-32. 在一个脚本中使用 cmp 来比较2个文件.

12-33. basename 和 dirname

12-34. 检查文件完整性

12-35. Uudecod 编码后的文件

12-36. 查找滥用的连接来报告垃圾邮件发送者

12-37. 分析一个垃圾邮件域

12-38. 获得一份股票报价

12-39. 更新 Fedora Core 4

12-40. 使用 ssh

12-41. 一个可以mail自己的脚本

12-42. 按月偿还贷款

12-43. 数制转换

12-44. 使用 "here document" 来调用 bc

12-45. 计算圆周率

12-46. 将10进制数字转换为16进制数字

12-47. 因子分解

12-48. 计算直角三角形的斜边

12-49. 使用 seq 来产生循环参数

12-50. 字母统计

12-51. 使用getopt来分析命令行选项

12-52. 一个拷贝自身的脚本

12-53. 练习dd

12-54. 记录按键

12-55. 安全的删除一个文件

12-56. 文件名产生器

12-57. 将米转换为英里

12-58. 使用 m4

13-1. 设置一个新密码

13-2. 设置一个擦除字符

13-3. 关掉终端对于密码的echo

13-4. 按键检测

13-5. Checking a remote server for identd<rojy bug>

13-6. pidof 帮助杀掉一个进程

13-7. 检查一个CD镜像

13-8. 在一个文件中创建文件系统

13-9. 添加一个新的硬盘驱动器

13-10. 使用umask来将输出文件隐藏起来

13-11. killall, 来自于 /etc/rc.d/init.d

14-1. 愚蠢的脚本策略

14-2. 从循环的输出中产生一个变量

14-3. 找anagram(回文构词法, 可以将一个有意义的单词, 变换为1个或多个有意义的单词, 但是还是原来的子母集合)

16-1. 使用exec重定向标准输入

16-2. 使用exec来重定向stdout

16-3. 使用exec在同一脚本中重定向stdin和stdout

16-4. 避免子shell

16-5. while循环的重定向

16-6. 另一种while循环的重定向

16-7. until循环重定向

16-8. for循环重定向

16-9. for循环重定向 loop (将标准输入和标准输出都重定向了)

16-10. 重定向if/then测试结构

16-11. 用于上面例子的"names.data"数据文件

16-12. 记录日志事件

17-1. 广播: 发送消息给每个登录上的用户

17-2. 仿造文件: 创建一个两行的仿造文件

17-3. 使用cat的多行消息

17-4. 带有抑制tab功能的多行消息

17-5. 使用参数替换的here document

17-6. 上传一个文件对到"Sunsite"的incoming目录

17-7. 关闭参数替换

17-8. 一个产生另外一个脚本的脚本

17-9. Here documents与函数

17-10. "匿名" here Document

17-11. 注释掉一段代码块

17-12. 一个自文档化(self-documenting)的脚本

17-13. 在一个文件的开头添加文本

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 list)"来测试命令行参数

25-2. 用"与列表"的另一个命令行参数测试

25-3. "或列表"和"与列表"的结合使用

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. 隐藏cookie而不再使用

28-2. 用/dev/zero创建一个交换临时文件

28-3. 创建ramdisk

29-1. 一个错误的脚本

29-2. 丢失关键字(keyword)

29-3. 另一个错误脚本

29-4. 用"assert"测试条件

29-5. 捕捉 exit

29-6. 在Control-C后清除垃圾

29-7. 跟踪变量

29-8. 运行多进程 (在多处理器的机器里)

31-1. 数字和字符串比较是不相等同的

31-2. 子SHELL缺陷

31-3. 把echo的输出用管道输送给read命令

33-1. shell 包装

33-2. 稍微复杂一些的shell包装

33-3. 写到日志文件的shell包装

33-4. 包装awk的脚本

33-5. 另一个包装awk的脚本

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. 整型还是string?

33-17. 传递和返回数组

33-18. anagrams游戏

33-19. 在shell脚本中调用的窗口部件

34-1. 字符串扩展

34-2. 间接变量引用 - 新方法

34-3. 使用间接变量引用的简单数据库应用

34-4. 用数组和其他的小技巧来处理四人随机打牌

A-1. mailformat: Formatting an e-mail message

A-2. rn: A simple-minded file rename utility

A-3. blank-rename: renames filenames containing blanks

A-4. encryptedpw: Uploading to an ftp site, using a locally encrypted password

A-5. copy-cd: Copying a data CD

A-6. Collatz series

A-7. days-between: Calculate number of days between two dates

A-8. Make a "dictionary"

A-9. Soundex conversion

A-10. "Game of Life"

A-11. Data file for "Game of Life"

A-12. behead: Removing mail and news message headers

A-13. ftpget: Downloading files via ftp

A-14. password: Generating random 8-character passwords

A-15. fifo: Making daily backups, using named pipes

A-16. Generating prime numbers using the modulo operator

A-17. tree: Displaying a directory tree

A-18. string functions: C-like string functions

A-19. Directory information

A-20. Object-oriented database

A-21. Library of hash functions

A-22. Colorizing text using hash functions

A-23. Mounting USB keychain storage devices

A-24. Preserving weblogs

A-25. Protecting literal strings

A-26. Unprotecting literal strings

A-27. Spammer Identification

A-28. Spammer Hunt

A-29. Making wget easier to use

A-30. A "podcasting" script

A-31. Basics Reviewed

A-32. An expanded cd command

C-1. Counting Letter Occurrences

K-1. Sample .bashrc file

L-1. VIEWDATA.BAT: DOS Batch File

L-2. viewdata.sh: Shell Script Conversion of VIEWDATA.BAT

P-1. Print the server environment