脚本rsync

rsync  时间:2021-01-12  阅读:()

Bash新手指南1/91BashGuideforBeginners中文版MachteltGarrelsXalasys.
comVersion1.
7Lastupdated20050905Edition翻译byWeiWangVersion1.
7Lastupdated20060105EditionBash新手指南2/91介绍.
21.
本指南诞生原因22.
谁应该阅读此书23.
新版本和取得方法.
24.
历史修订25.
贡献.
26.
反馈.
27.
版权信息28.
你需要什么29.
文档约定210.
本文档结构.
2第一章Bash和Bash脚本21.
1.
普通shell程序.
21.
1.
1.
shell的作用21.
1.
2.
shell类型.
21.
2.
Bash的优势21.
2.
1.
Bash是GNUShell.
21.
2.
2.
Bash独有的特性21.
3.
执行命令21.
3.
1.
概要21.
3.
2.
Shell内部命令21.
3.
3.
从脚本执行程序.
21.
4.
建立块.
21.
4.
1.
Shell建立块.
21.
5.
开发优良脚本.
21.
5.
1.
优良脚本的要素.
21.
5.
2.
结构21.
5.
3.
术语21.
5.
4.
有序且有逻辑性.
21.
5.
5.
一个Bash脚本的例子:mysystem.
sh.
21.
5.
6.
初始化脚本例子.
21.
6.
总结.
21.
7.
练习2第二章编写和调试脚本.
22.
1.
建立并且运行一个脚本22.
1.
1.
编写与命名22.
1.
2.
Script1.
sh22.
1.
3.
执行脚本.
22.
2.
脚本基础22.
2.
1.
哪个Shell来执行脚本22.
2.
2.
加入注释.
22.
3.
调试Bash脚本22.
3.
1.
调试整个脚本22.
3.
2.
调试部分脚本2Bash新手指南3/912.
4.
总结.
22.
5.
练习.
2第三章Bash环境23.
1.
Shell初始化文件.
23.
1.
1.
跨系统配置文件.
23.
1.
2.
单独用户配置文件23.
1.
3.
改变shell配置文件.
23.
2.
变量.
23.
2.
1.
变量的类型23.
2.
2.
建立变量.
23.
2.
3.
导出变量.
23.
2.
4.
保留变量.
23.
2.
5.
特殊参数.
23.
2.
6.
脚本通过变量循环23.
3.
引用字符23.
3.
1.
为何.
23.
3.
2.
转义字符.
23.
3.
3.
单引用23.
3.
4.
双引用23.
3.
5.
ANSIC引用23.
3.
6.
Locales.
4623.
4.
Shell扩展.
23.
4.
1.
概要23.
4.
2.
大括号表达式23.
4.
3.
波浪表达式23.
4.
4.
Shell参数和变量扩展.
23.
4.
5.
命令替换.
23.
4.
6.
算术表达式23.
4.
7.
替换的处理.
23.
4.
8.
Wordsplitting23.
4.
9.
文件名扩展23.
5.
别名.
23.
5.
1.
什么是别名23.
5.
2.
建立和消除别名.
23.
6.
更多Bash选项23.
6.
1.
显示选项.
23.
6.
2.
改变选项.
23.
7.
总结23.
8.
练习.
2第四章正则表达式24.
1.
正则表达式.
24.
1.
1.
什么是正则表达式24.
1.
2.
正则表达式metacharacters.
24.
1.
3.
Basicversus扩展正则表达式.
2Bash新手指南4/914.
2.
使用Grep的例子24.
2.
1.
什么是Grep24.
2.
2.
Grep与正则表达式.
24.
3.
模式匹配使用Bash特性24.
3.
1.
字符范围.
24.
3.
2.
字符classes24.
4.
总结.
24.
5.
练习.
2第五章GNUSED流编辑器25.
1.
介绍.
25.
1.
1.
什么是sed25.
1.
2.
sed命令25.
2.
交互编辑25.
2.
1.
打印包含pattern的行.
25.
2.
2.
删除包含pattern的输入行25.
2.
3.
行的范围.
25.
2.
4.
用sed查找替换.
25.
3.
非交互编辑25.
3.
1.
从文件读取sed命令.
25.
3.
2.
写输出文件25.
4.
总结.
25.
5.
练习.
2第六章GNUAWK编程语言26.
1.
gawk上路.
26.
1.
1.
什么是gawk26.
1.
2.
Gawk命令26.
2.
打印程序26.
2.
1.
打印选择的域26.
2.
2.
格式化块.
26.
2.
3.
打印命令和正则表达式.
26.
2.
4.
特殊的pattern.
26.
2.
5.
Gawk脚本26.
3.
Gawk变量.
26.
3.
1.
输入块的分隔符.
26.
3.
2.
输出的分隔符26.
3.
3.
记录的数量26.
3.
4.
用户定义变量26.
3.
5.
更多例子.
26.
3.
6.
printf程序26.
4.
总结.
26.
5.
练习.
2第七章条件语句.
27.
1.
介绍if27.
1.
1.
概要.
2Bash新手指南5/917.
1.
2.
if的简单应用.
27.
2.
更多if的高级使用方法.
27.
2.
1.
if/then/else结构.
27.
2.
2.
if/then/elif/else结构27.
2.
3.
if嵌套语句.
27.
2.
4.
布尔操作.
27.
2.
5.
使用exit语句和if27.
3.
使用case语句.
27.
3.
1.
简单的条件27.
4.
总结.
27.
5.
练习.
2第八章编写交互脚本.
28.
1.
显示用户消息28.
1.
1.
交互与否.
28.
1.
2.
使用内建echo命令28.
2.
捕获用户输入.
28.
2.
1.
使用内建read命令.
28.
2.
2.
提示用户输入28.
2.
3.
重定向和文件描述符28.
2.
4.
文件输入和输出.
28.
3.
总结.
28.
4.
练习.
2第九章重复性任务29.
1.
for循环.
29.
1.
1.
如何工作.
29.
1.
2.
例子29.
2.
while循环29.
2.
1.
Whatisit10829.
2.
2.
例子29.
3.
until循环29.
3.
1.
Whatisit11129.
3.
2.
例子29.
4.
I/O重定向和循环29.
4.
1.
输入重定向29.
4.
2.
输出重定向29.
5.
Break和continue29.
5.
1.
内建break29.
5.
2.
内建continue.
29.
5.
3.
例子29.
6.
Makingmenuswiththeselectbuiltin.
11529.
6.
1.
概要.
115.
29.
6.
2.
子菜单29.
7.
内建shift.
29.
7.
1.
Whatdoesitdo117.
2Bash新手指南6/919.
7.
2.
例子.
29.
8.
总结.
29.
9.
练习.
2第十章深入变量.
210.
1.
变量种类210.
1.
1.
概要assignmentofvalues.
.
.
.
.
.
.
.
120210.
1.
2.
使用内建declare210.
1.
3.
常量.
210.
2.
数组变量.
122.
210.
2.
1.
创建数组.
210.
2.
2.
Dereferencingthe变量inanarray.
122210.
2.
3.
删除数组变量210.
2.
4.
数组例子.
210.
3.
Operationson变量210.
3.
1.
Arithmeticon变量.
126210.
3.
2.
变量的长度.
210.
3.
3.
变量的转变.
210.
4.
总结210.
5.
练习2第十一章函数.
211.
1.
介绍211.
1.
1.
什么是函数211.
1.
2.
函数语法.
211.
1.
3.
函数中参数的位置.
211.
1.
4.
显示函数.
211.
2.
脚本中函数的例子211.
2.
1.
循环利用.
211.
2.
2.
设置路径.
211.
2.
3.
远程备份.
211.
3.
总结211.
4.
练习2第十二章捕捉信号212.
1.
信号212.
1.
1.
介绍.
212.
1.
2.
kill信号的使用212.
2.
陷阱212.
2.
1.
概要.
212.
2.
2.
Bash怎样解释陷阱.
212.
2.
3.
更多例子.
212.
3.
总结212.
4.
练习2附录AShell特性2A.
1.
常用特性.
2附录BGNU自由文档守则.
2Bash新手指南7/91介绍介绍介绍介绍1.
本指南诞生原因本指南诞生原因本指南诞生原因本指南诞生原因许多读者感到现有的HOWTO过于简短和不完整,同时那本ABS对于参考来说又过于庞大是撰写本文的主要原因,没有出现在介于两个极端之间教材.
我写本指南的主要由于缺乏免费的基本课程,尽管它们非常应该存在.
这是一本实用的指南,并不十分的严肃,尝试用实际的东西来代替那些理论的例子.
我分部分来写因为我对那些知道自己在谈论什么人写的脱离实际的和过分单纯的例子并不感到兴奋,展示一些比较酷的bash的特性,但是离开上下文环境后你无法在实际环境中使用.
你可以完成本书后再回过头去阅读那些能帮助你在现实世界生存的例子和练习.
以我自己是一名UNIX/Linux用户,系统管理员和培训人员的经验来说,我知道人们可以又几年中天天与他们的系统打交道,而不用知道任务自动控制的那些细小知识.
因此他们经常认为UNIX并不友好,更坏的是,他们产生了UNIX速度缓慢而又老掉牙的想法.
这个成了另外一个本指南想加以纠正的问题.
2.
谁应该阅读此书谁应该阅读此书谁应该阅读此书谁应该阅读此书每个在UNIX或者类UNIX系统上工作且想使生活变得简单的人以及系统管理员,能从阅读本书获益.
已经掌握通过命令行使系统运转的读者将会学到通过了解shell脚本使日常任务的执行变得安逸.
系统管理员依靠大量的shell脚本,日常任务通常使用一些简单脚本自动运行.
本文档充满例子将会鼓励你写出你自己的脚本而且鼓励你改进现有的脚本.
先决条件,不包含在本教程你应该是一个有经验的UNIX或者Linux用户,熟悉基本命令和man帮助文档能够使用文本编辑器理解系统启动和关闭进程,初始化和初始化脚本能建立用户和组,以及密码拥有相应权限,能进入不同模式理解设备,分区,挂载/卸载文件系统的名字约定在系统中安装/删除软件3.
新版本和新版本和新版本和新版本和取得方法取得方法取得方法取得方法最新版本可以在http://tille.
xalasys.
com/training/bash找到,你也可以在找到相同的版本http://tldp.
org/LDP/BashBeginnersGuide/html/index.
htmlFultus.
com已经有印刷版本.
Bash新手指南8/91图1.
封面4.
历史修订历史修订历史修订历史修订Revision1.
720050905Revisedby:MGCorrectedtyposinchapter3,6and7,incorporateduserremarks,addedanoteinchap7.
Revision1.
620050301Revisedby:MGMinordebugging,addedmorekeywords,infoaboutnewBash3.
0,tookoutblankimage.
Revision1.
520041206Revisedby:MGChangesbecauseofnewdomain,minorcorrections.
Revision1.
420041018Revisedby:MGDebugging,addedacoupleofnotesinchap9,replacedscreenshotswithscreensections.
Correctedsometypos.
Revision1.
320040709Revisedby:MGAddedtracerimage1x1pixelhttp://tille.
xalasys.
com/images/blankbash.
png,addedtextobjectsforallpictures,fixedwronglinksinindex,madesignallistmoreclear.
Revision1.
220040615Revisedby:MGAddedindex,moremarkupinscreensections.
Revision1.
120040522Revisedby:MGLastreadthroughbeforegoingtopress,addedmoreexamples,checkedsummaries,exercises,cleanedupintroduction.
Revision1.
020040427Revisedby:TMInitialreleaseforLDP;moreexercises,moremarkup,lesserrorsandabuse;addedglossary.
Revision1.
0beta20030420Revisedby:MGPrerelease5.
贡献贡献贡献贡献感谢所有帮助(或者尝试帮助)过我的所有朋友,还有我的丈夫;你的鼓励让这个艰难工作变成Bash新手指南9/91了可能.
感谢所有提交错误报告,例子,注释的人们.
·HansBol,oneofthegroupies·MikeSim,remarksonstyle·DanRichter,forarrayexamples·GergFerguson,forideasonthetitle·MendelLeoCooper,formakingroom·#linux.
be,forkeepingmyfeetontheground·FrankWang,forhisdetailedremarksonallthethingsIdidwrong;)特别感谢对本书作完整查阅和拼写语法错的TabathaMarshall.
我们创造了一个伟大的团队,我睡觉的时候她工作.
当然了,反之亦然.
6.
反馈反馈反馈反馈任何信息,错误等请写mail到7.
版权信息版权信息版权信息版权信息8.
你需要什么你需要什么你需要什么你需要什么9.
文档约定文档约定文档约定文档约定10.
本文档结构本文档结构本文档结构本文档结构第一章:Bash基础第二章:脚本基础第三章:Bash环境第四章:正则表达式第五章:Sed第六章:Awk第七章:条件语句第八章:交互脚本第九章:重复执行命令Bash新手指南10/91第一章第一章第一章第一章Bash和和和和Bash脚本脚本脚本脚本在这个介绍章节中,我们讨论一些常用的Shell指出GNUBash的优势和特性描述shell的块建立讨论Bash初始化文件观察Shell怎么执行命令察看一些简单的脚本1.
1.
普通普通普通普通shell程序程序程序程序1.
1.
1.
shell的作用的作用的作用的作用UNIX的shell程序解释用户的命令,不管是用户直接输入的或者从一个称作Shell脚本或者Shell程序文件读入.
Shell脚本是解释型的,而不是编译型的.
Shell从脚本行每行读取命令并在系统中搜索这些命令(seeSection1.
2),当编译器把一个程序转化为可供机器读取的可执行文件形式时,那么它就可以被用在shell脚本当中.
除了向内核传输命令之外,shell的主要任务是提供一个可单独配置的使用shell资源配置文件的用户环境.
1.
1.
2.
shell类型类型类型类型就像人们知道有不同的语言和方言一样,你的UNIX系统通常提供多种shell类型:sh或称BourneShell:最早的shell并且仍然在UNIX系统和UNIX相关系统中使用.
它是基本的shell,是一个特性不多的小程序.
虽然不是一个标准的shell,但是在每个和UNIX程序兼容的Linux系统上仍然存在.
bash或称BourneAgainshell:标准的GNUshell,直观而又灵活.
或许是初学者的最明智选择同时对高级和专业用户来说也是一个强有力的工具.
在Linux上,bash是普通用户的标准shell.
这个shell因此称为Bourneshell的超集,一套和插件.
意味着bash和sh是兼容的:在sh中可以工作的命令,在bash中也能工作,反之则不然.
本书所有的例子均使用Bashcsh或称Cshell:语法了类似于C语言,某些时候程序员会使用tcsh或称TurboCshell:asupersetofthecommon普通Cshell的一个超集,加强了的用户友好度和速度.
ksh或称theKornshell:某些时候被有UNIX背景的人所赏识.
Bourneshell的一个超集,标准配置对初学者来说就是一场恶梦.
文件/etc/shells给出了Linux系统上所有的已知shellmia:~>cat/etc/shells/bin/bash/bin/shBash新手指南11/91/bin/tcsh/bin/csh你默认的shell设置在文件/etc/passwd中,象下面这行对用户mia的设置mia:L2NOfqdlPrHwE:504:504:MiaMaya:/home/mia:/bin/bash要从一个shell转换到另外一个,只要在活动的终端里输入新shell的的名字.
系统在PATH设置的目录里面寻找,既然一个shell就是一个可执行的文件,当前的shell激活它使它运行起来,新的提示符出现,因为每个shell都有自己典型的外观:mia:~>tcsh[mia@post21~]$1.
2.
Bash的优势的优势的优势的优势1.
2.
1.
Bash是是是是GNUShellGNU计划(GNU'sNotUNIX)提供工具给类UNIX系统,象遵守UNIX标准的免费系统管理软件.
Bash是兼容sh的shell且从Kornshell(ksh)andCshell(csh)整合了一些有用的特性.
它遵循IEEEPOSIXP1003.
2/ISO9945.
2Shell和工具标准.
提供了基于sh的编程和交互的功能改进.
其中包括命令行编辑,无限制的历史命令,作业控制,shell函数和别名,无大小现实的索引数组,和以2到64为基础的整数算法.
Bash可以无修改地运行多数sh脚本.
和其他的GNU项目一样,bash主动开始保留,保护和促进使用,学习,拷贝,修改和再发布软件的自由.
普遍认为这样的情况激励了创造力.
这也是bash程序可以而许多其他shell无法提供的额外特性.
1.
2.
2.
Bash独有的特性独有的特性独有的特性独有的特性1.
2.
2.
1.
改进改进改进改进除了单字符shell命令行选项可以通常使用内建命令set来配置外,你还可以使用几种多字符选项.
我们会在本章和后继章节中一系列的更流行的选项中留下深刻印象;完整的列表可以在Bash的信息页面中找到,Bash特性->调用Bash.
1.
2.
2.
2.
Bash启动文件启动文件启动文件启动文件启动文件是当Bash启动时候读取并且执行的脚本.
下面的部分描述了启动shell,和读取启动文件的不同途径.
1.
2.
2.
2.
1.
以交互登以交互登以交互登以交互登陆陆陆陆shell调用,或者使用调用,或者使用调用,或者使用调用,或者使用`--login`交互意味着你可以输入命令.
Shell没有运行因为一个脚本被激活了.
一个登陆shell就是在系统验证完了你输入的用户名和密码后得到shell.
读取的文件:/etc/profile~/.
bash_profile,~/.
bash_login或者~/.
profile:读取第一个存在的可读取的文件Bash新手指南12/91~/.
bash_logout退出登陆错误消息将会显示如果配置文件存在但是不能读取.
一个文件不存在,Bash将搜索下一个.
1.
2.
2.
2.
2.
以以以以一个一个一个一个交互交互交互交互非非非非登登登登陆陆陆陆shell调用调用调用调用一个非登陆shell就是不需要进行系统的认证.
比如,通过一个图标打开一个终端,或者一个菜单项目,那样就是非登陆shell.
读取的文件:~/.
bashrc此文件通常指向~/.
bash_profile:if[-f~/.
bashrc];then.
~/.
bashrc;fi参阅第七章获取if结构的详细信息1.
2.
2.
2.
3.
非交互非交互非交互非交互调用调用调用调用所有脚本使用费交互shell.
他们是被编制出来完成特定任务且不能完成其他工作.
读取的文件:由环境变量BASH_ENV定义搜索此文件时候不使用环境变量PATH,所以若是你想使用它,最好给出全部路径名和文件名来.
1.
2.
2.
2.
4.
以以以以sh命令命令命令命令调用调用调用调用Bash尝试sh的相似行为同时也遵循POSIX标准.
读取的文件:/etc/profile~/.
profile当以交互方式调用时,环境变量ENV能指出额外的启动信息.
1.
2.
2.
2.
5.
POSIX模式模式模式模式本选项在使用内建的set命令:set-oposix或者再以–posix选项调用bash程序时候被激活.
Bash会试着尝试尽可能遵循POSIX的shell标准.
同样可以设置POSIXLY_CORRECT变量来达到目的.
读取的文件:在环境变量ENV中定义.
1.
2.
2.
2.
6.
远程调用远程调用远程调用远程调用Bash新手指南13/91调用rshd读取的文件:~/.
bashrc禁止使用r系列工具要注意使用类似rlogin,telnet,rsh,rcp工具的危险.
由于他们在网络上传输数据是未经过加密的所以他们本质上是不安全的.
如果你需要远程执行和文件传输之类的工具,推荐使用SSH,从http://www.
openssh.
org下载,不同的客户端程序已经出现非UNIX系统上,请察看本地的软件镜象.
1.
2.
2.
2.
7.
.
.
.
当当当当UID(用户(用户(用户(用户ID)不等于)不等于)不等于)不等于EUID时候调用时候调用时候调用时候调用此种方式无起始文件读取.
1.
2.
2.
3.
交互交互交互交互shell1.
2.
2.
3.
1.
什么是交互什么是交互什么是交互什么是交互shell交互shell通常在用户终端读取并且输入:输入输出都连接到终端.
Bash启动交互行为当bash以无选项方式调用,除了选项以字符串读取或者shell1.
2.
2.
3.
2.
这个这个这个这个shell是交互的吗是交互的吗是交互的吗是交互的吗1.
3.
执行命令执行命令执行命令执行命令1.
3.
1.
概要概要概要概要Bash会确定执行的程序的类型.
普通程序是那些已经为你的系统编译好的系统命令.
当这样的程序运行的时候,Bash创建一个自身的拷贝因此一个新的进程就被创建.
子进程和父进程拥有一样的环境,唯一个区别只有进程号.
这个过程被称作内核空间创建进程(Forking).
在内核空间创建进程后,子进程的地址空间被新进程数据覆盖.
此步骤通过exec系统调用完成.
fork-and-exec机制因此把旧的命令转化成新的.
这种机制用来创建所有的UNIX进程,因此对Linux操作系统也起作用,甚至是第一个进程,进程号是1的init,也是在称为bootstrapping的启动过程中被fork的.
Bash新手指南14/911.
3.
2.
Shell内部命令内部命令内部命令内部命令内建的命令包含在shell本身里面.
当内建的命令的名字被用作一个简单命令的第一个词时,shell直接执行那个命令,而不创建新的进程.
内建的命令是实现bash支持3种内建的命令:1.
3.
3.
从脚本执行程序从脚本执行程序从脚本执行程序从脚本执行程序当程序被一个脚本来执行,bash会使用fork创建一个新的bash进程.
这个子shell一次从shell脚本中读取一行.
每行的命令如果直接来自键盘的话会被读取,翻译和执行当子shell处理脚本中的每一行时,父进程等待子进程结束.
当运行万shell脚本中每一行时,子shell就结束.
父shell苏醒并且显示一个新的提示符.
1.
4.
建立块建立块建立块建立块1.
4.
1.
Shell建立块建立块建立块建立块1.
4.
1.
1.
Shell语法语法语法语法1.
4.
1.
2.
Shell命令命令命令命令一个简单的shell命令例如touchfile1file2file3由命令本身,参数以及空格构成.
更复杂的shell命令由简单的命令以多种方式组织在一起:例如管道把一个命令的输出变成另外一个命令的输入,循环或者条件结构,或者其他的组织方式.
请看一些例子:ls|moregunzipfile.
tar.
gz|tarxvf-1.
4.
1.
3.
Shell函数函数函数函数Shell函数是一种为一组之后执行的命令命名一个名字.
他们执行起来就像"普通"命令.
当一个Shell函数的名字被一个简单命令使用后,和函数名字相关联的命令就会执行.

Shell函数会在当前shell下执行,不会有新的进程创建来打断它们.
1.
4.
1.
4.
Shell参数参数参数参数参数是储存值得实体.
可以一个名字,一个数字或者一个特别的值.
从shell的目的来看,变量是一个存储名字的参数.
一个变量拥有一个值,零或者更多的属性.
变量是用shell内建命令declare来建立的.
Bash新手指南15/91如果没有赋予任何值,变量就被赋于空字符串.
变量只能使用内建命令unset来移除.
在3.
2节将讨论对变量赋值,第十章将会讨论高级使用方法.
1.
4.
1.
5.
Shell表达式表达式表达式表达式Shell表达式是在每一行分成几部分后执行的.
以下是表达式的类型大括号表达式波浪号表达式参数和变量表达式命令替换表达式算术表达式字分离表达式文件名表达式在3.
4节我们将详细讨论这些表达式1.
4.
1.
6.
重定向重定向重定向重定向在一个命令执行之前,它可能借助shell翻译的一个特殊的符号重定向它的输入输出.
重定向也可以用来为现有的shell执行环境打开和关闭文件.
1.
4.
1.
7.
执行命令执行命令执行命令执行命令当执行一个命令的时候,1.
4.
1.
8.
Shell脚本脚本脚本脚本调用bash时,当一个包含shell命令的文件被用作第一个非选项参数时候(不带-c或者-s,这两个参数将会创建一个非交互的shell).
这个shell首先搜寻脚本文件所在的当前目录,如果没有找到则对环境变量PATH进行查找.
1.
5.
开发优良脚本开发优良脚本开发优良脚本开发优良脚本1.
5.
1.
优良脚本的要素优良脚本的要素优良脚本的要素优良脚本的要素本指南只要是关于上面的shell构成部分,脚本.
在继续之前我们应该考虑一些东西:1.
一个脚本应该无错运行Bash新手指南16/912.
它应该完成他要完成的任务3.
程序的逻辑结构定义清晰而且明显4.
一个脚本不做不必要的工作5.
脚本可以重用1.
5.
2.
结构结构结构结构1.
5.
3.
术语术语术语术语1.
5.
4.
有序且有逻辑性有序且有逻辑性有序且有逻辑性有序且有逻辑性1.
5.
5.
一个一个一个一个Bash脚本的例子:脚本的例子:脚本的例子:脚本的例子:mysystem.
sh1.
5.
6.
初始化脚本例子初始化脚本例子初始化脚本例子初始化脚本例子1.
6.
总结总结总结总结Bash是GNUshell,兼容sh以及其他shell里的许多有用的特性.
当shell启动的时候,它读取它自己的配置文件.
最重要的几个如下所示:/etc/profile~/.
bash_profile~/.
bashrcBash在交互模式下,遵循POSIX标准的时候和限制模式下的行为会有所不同.
shell命令可以分成为3个种类:shell的功能命令,shell内建命令和你系统里某个目录里的命令.
Bash支持额外的sh不包含的内建命令.
Shell脚本把那些命令组成shell语法命令.
脚本读取一行执行一行且应该有逻辑结构.
1.
7.
练习练习练习练习Bash新手指南17/91第二章第二章第二章第二章编写和调试脚本编写和调试脚本编写和调试脚本编写和调试脚本经过学习本章节,你将能够:写简单的脚本定义shell类型来运行脚本在脚本中加入注释改变脚本的权限执行并且调试脚本2.
1.
建立并且运行一个脚本建立并且运行一个脚本建立并且运行一个脚本建立并且运行一个脚本2.
1.
1.
编写与命名编写与命名编写与命名编写与命名一个shell脚本是你重复使用的命令序列.
这个序列通常是通过在命令行输入整个脚本的命令来执行的.
或者,你可以使用cron工具来使脚本自动执行任务.
另外脚本也可以用于UNIX的启动和关闭过程中定义在init脚本中的守护程序和服务的操作.
要建立一个shell脚本,在你的编辑器中打开一个新的空白文件.
任何文本编辑器就可以:vim,emacs,gedit,dtpad都可以.
可能你会选择一个高级的编辑器比如vim或者emacs,因为它们可以设置来高亮语法来帮助初学者避免很多经常犯的错误,比如忘记括号和冒号.

把UNIX命令放在一个新的空白文件里,就象在命令行输入命令.
就像先前的讨论(参阅1.
3节),命令可以作为shell函数,shell组成部分,UNIX命令和其他脚本.
为你的脚本起一个合理的名字来提醒自己脚本的作用.
确定你的脚本的名字和已经存在的命令是没有冲突的.
为了保证不会引起混乱,脚本名字经常以.
sh结尾.
尽管如此,还是有可能你选择的脚本名字已经和系统中原来的是相同的.
使用which,whereis和一些其他命令来查找程序的文件的信息:which-ascript_namewhereisscript_namelocatescript_name2.
1.
2.
Script1.
sh在本例子中我们使用bash内建命令echo在此任务运行建立输出之前来通知用户将发生什么.
强烈建议告知用户脚本的用途,因为本脚本什么事都不干防止用户变得过于紧张.
我们会在第八章继续如何通知用户.
Bash新手指南18/91正好自己写一下脚本.
建立一个目录~/scripts来存放你的脚本将会是个好主意.
把此目录添加到PATH变量中:exportPATH="$PATH:~/scripts"如果你才开始使用Bash,最好使用一个给不同结构以不同颜色的文本编辑器.
vim,gvim,(x)emacs,kwrite和许多其他支持语法高亮的编辑器;详细请察看编辑器的文档.
不同的提示符不同的提示符不同的提示符不同的提示符本教程的提示符的改变都依赖作者的心情.
相对于标准的$提示符他更接近之际情况.
唯一的约定就是,root提示符以#结尾.
2.
1.
3.
执行脚本执行脚本执行脚本执行脚本为了能使当前用户运行脚本,它应该有可执行权限.
在设置权限时,检查你是否得到你想要得权限.
完成后脚本就可以象其他命令一样运行.
willy:~/scripts>chmodu+xscript1.
shwilly:~/scripts>lslscript1.
shrwxrwr1willywilly456Dec2417:11script1.
shwilly:~>script1.
shBash新手指南19/91Thescriptstartsnow.
Hi,willy!
Iwillnowfetchyoualistofconnectedusers:3:38pmup18days,5:37,4users,loadaverage:0.
12,0.
22,0.
15USERTTYFROMLOGIN@IDLEJCPUPCPUWHATroottty2Sat2pm4:25m0.
24s0.
05sbashwilly:0Sat2pm0.
00swillypts/3Sat2pm3:33m36.
39s36.
39sBitchXwillyirwillypts/2Sat2pm3:33m0.
13s0.
06s/usr/bin/screenI'msettingtwovariablesnow.
Thisisastring:blackAndthisisanumber:9I'mgivingyoubackyourpromptnow.
willy:~/scripts>echo$COLOURwilly:~/scripts>echo$VALUEwilly:~/scripts>这是执行脚本最普通的方法.
在子shell中一般都是这么执行脚本.
建立在子shell中的变量,函数和别名等只有子shell使用.
当那个shell退出,父shell重新得到控制的时候,所有的东西都被清空,脚本对shell状态所作的改变耶全部清除.
如果你没有把脚本的目录放到PATH里面,当前目录也不在PATH变量中,那么你可以这样来执行脚本:.
/script_name.
sh脚本也可以被明确地指定shell执行,不过通常我们只有在想得到特殊的行为时候才这样做,比如脚本是否能在另外一个shell里面工作或者打印调试的信息.
rbashscript_name.
shshscript_name.
shbashscript_name.
sh特定的shell会成为当前shell子shell来运行脚本.
当你想以特殊的选项或者以脚本没有指定的特殊条件来启动脚本时候可以这么做.
如果你想在当前脚本执行脚本而不想启动一个新的shell,你可以使用source:sourcescript_name.
shsource=.
Bash的内建命令source和sh的.
命令是相同的.
这里脚本不需要可执行权限.
命令在当前shell力执行,所以任何对环境的改变,将在脚本结束时同样起作用.
willy:~/scripts>sourcescript1.
shBash新手指南20/91outputommittedwilly:~/scripts>echo$VALUE9willy:~/scripts>2.
2.
脚本基础脚本基础脚本基础脚本基础2.
2.
1.
哪个哪个哪个哪个Shell来执行脚本来执行脚本来执行脚本来执行脚本当在子shell运行脚本时,你应该定义哪个shell来运行脚本,你编写的脚本的shell类型可能不是你系统默认的,所以用错误的shell来运行你输入的命令可能最终出错.
第一行决定了启动的shell,第一行的开始2个字符应该是#!
,然后紧跟解释后面命令的shell的路径.
空白行也被认为是一行,所以不要让你的脚本以空白行开始.
出于本教程的考虑,所有的脚本都这样开头:#!
/bin/bash先前提到过,这样表明bash可以在/bin里面找到.
2.
2.
2.
加入注释加入注释加入注释加入注释你应该知道事实上你不会阅读你自己脚本的唯一的一个人.
很多用户和系统管理员运行别人编写的脚本.
如果他们想知道你是如何做到的,注释能很好的提醒读者.
注释也同样让你自己更方便.
你一定阅读了很多帮助页面通过脚本中的一些命令来得到特定的结果.
如果不对脚本加上注释,几个星期或者几个月后你需要更改你的脚本,你会忘记脚本做了些什么事,你怎么做的和为什么要做.
把script1.
sh例子拷贝到commented-script1.
sh,编辑注释来反映脚本的作用.
在#后面的行被忽略而且只能在打开脚本时才能看到.
#!
/bin/bash#Thisscriptclearstheterminal,displaysagreetingandgivesinformation#aboutcurrentlyconnectedusers.
Thetwoexamplevariablesaresetanddisplayed.
clear#clearterminalwindowecho"Thescriptstartsnow.
"echo"Hi,$USER!
"#dollarsignisusedtogetcontentofvariableechoecho"Iwillnowfetchyoualistofconnectedusers:"echow#showwhoisloggedonandecho#whattheyaredoingecho"I'msettingtwovariablesnow.
"Bash新手指南21/91COLOUR="black"#setalocalshellvariableVALUE="9"#setalocalshellvariableecho"Thisisastring:$COLOUR"#displaycontentofvariableecho"Andthisisanumber:$VALUE"#displaycontentofvariableechoecho"I'mgivingyoubackyourpromptnow.
"echo在一个良好的脚本中,第一行经常注明要完成的任务.
然后为了明确每一大块命令将被加上注释.
作为一个例子,Linux的初始脚本,在你系统里的init.
d目录下,为了能让每个使用Linux的人读取和更改它,通常都作了良好的注释.
2.
3.
调试调试调试调试Bash脚本脚本脚本脚本2.
3.
1.
调试整个脚本调试整个脚本调试整个脚本调试整个脚本当一些事情不能按照计划进行,你需要确定到底是什么导致了脚本运行失败.
Bash提供了大量的调试特性.
最通常的做法是使用-x选项来启动子shell,这将让整个脚本在调试模式下进行.
每个命令和他附加参数的信息会在执行之前被展开并且送到标准输出打印.

以下是脚本commented-script1.
sh在调试模式下运行.
再次注意在脚本的输出中注释是不可见的.
willy:~/scripts>bashxscript1.
sh+clear+echo'Thescriptstartsnow.
'Thescriptstartsnow.
+echo'Hi,willy!
'Hi,willy!
+echo+echo'Iwillnowfetchyoualistofconnectedusers:'Iwillnowfetchyoualistofconnectedusers:+echo+w4:50pmup18days,6:49,4users,loadaverage:0.
58,0.
62,0.
40USERTTYFROMLOGIN@IDLEJCPUPCPUWHATroottty2Sat2pm5:36m0.
24s0.
05sbashwilly:0Sat2pm0.
00swillypts/3Sat2pm43:1336.
82s36.
82sBitchXwillyirwillypts/2Sat2pm43:130.
13s0.
06s/usr/bin/screen+echo+echo'I'\''msettingtwovariablesnow.
'I'msettingtwovariablesnow.
+COLOUR=black+VALUE=9+echo'Thisisastring:'Bash新手指南22/91Thisisastring:+echo'Andthisisanumber:'Andthisisanumber:+echo+echo'I'\''mgivingyoubackyourpromptnow.
'I'mgivingyoubackyourpromptnow.
+echo未来bash的特性现在有一个全新的Bash调式工具出现在SourceForge.
然而现在,你需要一个已经打过补丁的Bash-2.
05.
新的特性可能会在bash-3.
0中出现.
2.
3.
2.
调试部分脚本调试部分脚本调试部分脚本调试部分脚本使用bash内建命令set可以让那些确定没有错误的部分以正常模式运行,而只对有错误的部分显示其debug信息.
比如我们不确定在commented-script1.
sh里面w命令会做些什么,那么我们可以把它象这样包含起来:setx#activatedebuggingfromherewset+x#stopdebuggingfromhere输出看来就像这样:willy:~/scripts>script1.
shThescriptstartsnow.
Hi,willy!
Iwillnowfetchyoualistofconnectedusers:+w5:00pmup18days,7:00,4users,loadaverage:0.
79,0.
39,0.
33USERTTYFROMLOGIN@IDLEJCPUPCPUWHATroottty2Sat2pm5:47m0.
24s0.
05sbashwilly:0Sat2pm0.
00swillypts/3Sat2pm54:0236.
88s36.
88sBitchXwillykewillypts/2Sat2pm54:020.
13s0.
06s/usr/bin/screen+set+xI'msettingtwovariablesnow.
Thisisastring:Andthisisanumber:I'mgivingyoubackyourpromptnow.
willy:~/scripts>你可以在同样的脚本里多次打开关闭调试模式.
下表给出了其他有用的bash选项概貌Bash新手指南23/91Table21.
OverviewofsetdebuggingoptionsShortnotationLongnotationResultsetfsetonoglobDisablefilenamegenerationusingmetacharacters(globbing).
setvsetoverbosePrintsshellinputlinesastheyareread.
setxsetoxtracePrintcommandtracesbeforeexecutingcommand.
横线用来激活一个shell选项,再使用一次将解除.
不要搞错了.
以下例子,我们在命令行里面证明这些选项.
willy:~/scripts>set-vwilly:~/scripts>lslscommentedscripts.
shscript1.
shwilly:~/scripts>set+vset+vwilly:~/scripts>ls*commentedscripts.
shscript1.
shwilly:~/scripts>set-fwilly:~/scripts>ls*ls:*:Nosuchfileordirectorywilly:~/scripts>touch*willy:~/scripts>ls*commentedscripts.
shscript1.
shwilly:~/scripts>rm*willy:~/scripts>lscommentedscripts.
shscript1.
sh或者,这些模式也可以在脚本里面指定,只需在第一行shell的声明中加入需要的选项.
选项可以叠加,和通常UNIX命令一样:#!
/bin/bash-xv每当你找到脚本中的错误部分,你可以在每个你不确定的命令之前增加echo语句,这样你就会明确的看到哪里或者为什么脚本没有正常工作.
在commented-script1.
sh例子中,可以这么做,依然假设显示用户这部分出了问题:echo"debugmessage:nowattemptingtostartwcommand";w在更高级的脚本中,echo可以插入到在不同的阶段显示变量表,因此可以检查到错误:echo"VariableVARNAMEisnowsetto$VARNAME.
"2.
4.
总结总结总结总结shell脚本是一个放在可执行文本文件中的一组可以重用的命令.
任何文本编辑器都可以用来编Bash新手指南24/91写脚本.
脚本以#!
开头,后面紧跟执行脚本的shell的路径.
在脚本中加入注释是为了将来的参考,同样也使得其他人能理解脚本.
解释多肯定比少要好.
使用选项可以用来调试脚本.
shell选项可以用来部分或者扫描整个脚本.
善用echo你某些位置也是一种常用的排错技术.
2.
5.
练习练习练习练习Bash新手指南25/91第三章第三章第三章第三章Bash环境环境环境环境本章我们讨论几种能影响Bash环境的不同方法编辑shell初始化文件使用变量使用不同引用风格实现算术计算指派别名使用扩充和替换3.
1.
Shell初始化文件初始化文件初始化文件初始化文件3.
1.
1.
跨系统跨系统跨系统跨系统配置配置配置配置文件文件文件文件3.
1.
1.
1.
/etc/profile当用--login选项或者以sh来来调用交互模式时,Bash读取/etc/profile的指令.
通常是一些设置shell变量PATH,USER,MAIL,HOSTNAME和HISTSIZE.
再某些系统上,umask的值在/etc/profile中配置;其他的一些系统中这个文件包含了指向了其他配置文件的指针:/etc/inputrc,可以配置命令行响铃风格的跨系统的行读取初始化文件.
/etc/profile.
d目录,包含了配置特别程序的跨系统行为的文件.
你想应用到所有用户环境的所有设置都必须在这个文件中,这个文件看上去像这样:#/etc/profile#Systemwideenvironmentandstartupprograms,forloginsetupPATH=$PATH:/usr/X11R6/bin#NocorefilesbydefaultulimitSc0>/dev/null2>&1USER="`idun`"LOGNAME=$USERMAIL="/var/spool/mail/$USER"HOSTNAME=`/bin/hostname`HISTSIZE=1000#Keyboard,bell,displaystyle:thereadlineconfigfile:if[z"$INPUTRC"a!
f"$HOME/.
inputrc"];thenINPUTRC=/etc/inputrcfiPS1="\u@\h\W"exportPATHUSERLOGNAMEMAILHOSTNAMEHISTSIZEINPUTRCPS1#Sourceinitializationfilesforspecificprograms(ls,vim,less,.
.
.
)foriin/etc/profile.
d/*.
sh;doBash新手指南26/91if[r"$i"];then.
$ifidone#Settingsforprograminitializationsource/etc/java.
confexportNPX_PLUGIN_PATH="$JRE_HOME/plugin/ns4plugin/:/usr/lib/netscape/plugins"PAGER="/usr/bin/less"unseti3.
1.
2.
单独用户单独用户单独用户单独用户配置配置配置配置文件文件文件文件我没有这些文件!
默认情况下这些文件可能在你的主目录中,需要的话也可以建立他们.
3.
1.
2.
1.
~/.
bash_profile这是单独为用户配置环境的首选的配置文件.
在这个文件中,用户可以增加额外的配置选项或者改变默认设置:franky~>cat.
bash_profile###.
bash_profilefile####Executedfromthebashshellwhenyoulogin.
###source~/.
bashrcsource~/.
bash_logincase"$OS"inIRIX)sttysanedecsttyerase;;#SunOS)#sttyerase#;;*)sttysane;;esac这个用户配置了登陆到不同操作系统的退格字符.
除此之外,用户的.
bashrc和.
bash_login也被读取.
Bash新手指南27/913.
1.
2.
2.
~/.
bash_login这个文件包含了只有在你登陆进系统的才执行的特殊的设置.
在这个例子中,我用它来配置umask的值来显示一个当前连接的用户列表.
该用户也得到了当前月的日历.
###Bash_loginfile####commandstoperformfromthebashshellatlogintime##(sourcedfrom.
bash_profile)####fileprotectionumask002#alltome,readtogroupandothers#miscellaneouswcal`date+"%m"``date+"%Y"`在没有~/.
bash_profile的情况下,这个文件就被读取.
3.
1.
2.
3.
~/.
profile在没有~/.
bash_profile和~/.
bash_login的情况下,~/.
profile就被读取.
他能保存一些可以被别的shell访问的配置.
注意其他的shell可能不能识别Bash的语法.
3.
1.
2.
4.
~/bashrc如今,更加普遍的是使用一个非登陆shell,比如使用X终端窗口登陆进图形模式的时候.
打开一个这样的窗口之后,用户不需要提供用户名和密码;无需认证.
此时Bash会搜索~/.
bashrc,所以也指向登陆时读取得文件,同时也意味着你不需要在多个文件中输入相同的设置.

在这个用户的.
bashrc里,在读取了跨系统的/etc/bashrc之后定义了一些别名和为特定的程序使用的变量.
franky~>cat.
bashrc#/home/franky/.
bashrc#Sourceglobaldefinitionsif[f/etc/bashrc];then.
/etc/bashrcfi#shelloptionssetonoclobber#myshellvariablesBash新手指南28/91exportPS1="\[\033[1;44m\]\u\w\[\033[0m\]"exportPATH="$PATH:~/bin:~/scripts"#myaliasesaliascdrecord='cdrecorddev0,0,0speed=8'aliasss='sshoctarine'aliasll='lsla'#mozillafixMOZILLA_FIVE_HOME=/usr/lib/mozillaLD_LIBRARY_PATH=/usr/lib/mozilla:/usr/lib/mozilla/pluginsMOZ_DIST_BIN=/usr/lib/mozillaMOZ_PROGRAM=/usr/lib/mozilla/mozillabinexportMOZILLA_FIVE_HOMELD_LIBRARY_PATHMOZ_DIST_BINMOZ_PROGRAM#fontfixaliasxt='xtermbgblackfgwhite&'#BitchXsettingsexportIRCNAME="frnk"#THEENDfranky~>更多的例子能在bash的包内找到.
记住例子可能需要修改才能在你的环境内工作.
别名将在3.
5.
节讨论.
3.
1.
2.
5.
~/.
bash_logout这个文件包含了登出系统时候的特别指令.
在这个例子中,终端窗口在登出的时候被清空.
在关闭时留下一个干净的窗口对远程连接来说非常有用.
franky~>cat.
bash_logout###Bash_logoutfile####commandstoperformfromthebashshellatlogouttime###clearfranky~>3.
1.
3.
改变改变改变改变shell配置配置配置配置文件文件文件文件当对上述文件进行任何修改的时候,用户可以重新连接到系统,或者source这个改变的文件来生效.
这样解释脚本的话,修改就应用到现在的shell.
Bash新手指南29/91图3-1.
不同用户的不同提示多数shell脚本在一个私有环境中执行:除非变量是父脚本export出来的,不然他们不会被子进程继承下来.
3.
2.
变量变量变量变量3.
2.
1.
变量变量变量变量的类型的类型的类型的类型正如上面的例子,shell变量约定俗成地用大写表示.
Bash保留两种类型的变量列表:3.
2.
1.
1.
全局变量全局变量或者环境变量存在于所有的shell里面.
env和printenv命令能够通常用于显示环境变量.
这些程序在sh-utils包内.
下面是一个典型的输出:franky~>printenvCC=gccCDPATH=.
:~:/usr/local:/usr:/CFLAGS=O2fomitframepointerCOLORTERM=gnometerminalCXXFLAGS=O2fomitframepointerDISPLAY=:0DOMAIN=hq.
xalasys.
come=TOR=viFCEDIT=viBash新手指南30/91FIGNORE=.
o:~G_BROKEN_FILENAMES=1GDK_USE_XFT=1GDMSESSION=DefaultGNOME_DESKTOP_SESSION_ID=DefaultGTK_RC_FILES=/etc/gtk/gtkrc:/nethome/franky/.
gtkrc1.
2gnome2GWMCOLOR=darkgreenGWMTERM=xtermHISTFILESIZE=5000history_control=ignoredupsHISTSIZE=2000HOME=/nethome/frankyHOSTNAME=octarine.
hq.
xalasys.
comINPUTRC=/etc/inputrcIRCNAME=frankyJAVA_HOME=/usr/java/j2sdk1.
4.
0LANG=en_USLDFLAGS=sLD_LIBRARY_PATH=/usr/lib/mozilla:/usr/lib/mozilla/pluginsLESSCHARSET=latin1LESS=edfMQLESSOPEN=|/usr/bin/lesspipe.
sh%sLEX=flexLOCAL_MACHINE=octarineLOGNAME=frankyLS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:MACHINES=octarineMAILCHECK=60MAIL=/var/mail/frankyMANPATH=/usr/man:/usr/share/man/:/usr/local/man:/usr/X11R6/manMEAN_MACHINES=octarineMOZ_DIST_BIN=/usr/lib/mozillaMOZILLA_FIVE_HOME=/usr/lib/mozillaMOZ_PROGRAM=/usr/lib/mozilla/mozillabinMTOOLS_FAT_COMPATIBILITY=1MYMALLOC=0NNTPPORT=119NNTPSERVER=newsNPX_PLUGIN_PATH=/plugin/ns4plugin/:/usr/lib/netscape/pluginsOLDPWD=/nethome/frankyOS=LinuxPAGER=lessPATH=/nethome/franky/bin.
Linux:/nethome/franky/bin:/usr/local/bin:/usr/local/sbin:/usr/X11R6/bin:/PS1=\[\033[1;44m\]frankyisin\w\[\033[0m\]Bash新手指南31/91PS2=Moreinput>PWD=/nethome/frankySESSION_MANAGER=local/octarine.
hq.
xalasys.
com:/tmp/.
ICEunix/22106SHELL=/bin/bashSHELL_LOGIN=loginSHLVL=2SSH_AGENT_PID=22161SSH_ASKPASS=/usr/libexec/openssh/gnomesshaskpassSSH_AUTH_SOCK=/tmp/sshXXmhQ4fC/agent.
22106START_WM=twmTERM=xtermTYPE=typeUSERNAME=frankyUSER=franky_=/usr/bin/printenvVISUAL=viWINDOWID=20971661XAPPLRESDIR=/nethome/franky/appdefaultsXAUTHORITY=/nethome/franky/.
XauthorityXENVIRONMENT=/nethome/franky/.
XdefaultsXFILESEARCHPATH=/usr/X11R6/lib/X11/%L/%T/%N%C%S:/usr/X11R6/lib/X11/%l/%T/%N%C%S:/usr/X11R6/lib/X11/%XKEYSYMDB=/usr/X11R6/lib/X11/XKeysymDBXMODIFIERS=@im=noneXTERMID=XWINHOME=/usr/X11R6X=X11R6YACC=bisony3.
2.
1.
2.
本地变量本地变量只存在于当前shell.
使用内建的不带选项的set命令将显示所有变量的列表(包括环境变量)和函数.
输出会根据当前的设置排列而且以可以重用的方式显示.

以下是在退出了同样被set命令显示的函数之后,比较printenv和set的输出的文件.
franky~>diffset.
sortedprintenv.
sorted|grep"export1number=1bash:export:`1number=1':notavalididentifier在shell中设置一个变量,使用:VARNAME="value"Bash新手指南33/91在等号周围放置空格会造成错误.
在对变量赋值得时候把内容字符串用引号引起来是一个良好的习惯:这样会降低你出错的机会.
一些实用大小写,数字和空格的例子:franky~>MYVAR1="2"franky~>echo$MYVAR12franky~>first_name="Franky"franky~>echo$first_nameFrankyfranky~>full_name="FrankyM.
Singh"franky~>echo$full_nameFrankyM.
Singhfranky~>MYVAR2="2"bash:MYVAR2=2:commandnotfoundfranky~>MYVAR1="2"bash:MYVAR1:commandnotfoundfranky~>MYVAR1="2"bash:2:commandnotfoundfranky~>unsetMYVAR1first_namefull_namefranky~>echo$MYVAR1$first_name$full_namefranky~>3.
2.
3.
导出导出导出导出变量变量变量变量一个变量的建立就像上面的例子那样仅仅存在于当前shell.
他是本地变量:当前shell的子进程不会意识到这个的存在.
为了八变量传递到子shell,我们需要使用内建的export命令把他们export出来.
被export出来的变量就像环境变量一样,设置和export变量通常用下面一步来完成:exportVARNAME="value"一个子shell能够改变从父shell变量继承过来的变量,但是在子shell所作的改变对父shell也没有影响.
下面的例子来证明这个:franky~>full_name="FrankyM.
Singh"franky~>bashfranky~>echo$full_namefranky~>exitfranky~>exportfull_namefranky~>bashfranky~>echo$full_nameBash新手指南34/91FrankyM.
Singhfranky~>exportfull_name="CharlestheGreat"franky~>echo$full_nameCharlestheGreatfranky~>exitfranky~>echo$full_nameFrankyM.
Singhfranky~>当第一次尝试在子shell里面读取full_name的值时,它并不存在(echo显示了一个空字符串).
子shell退出,然后full_name在父shell里面export,一个变量在赋值后仍然可以被export.
然后一个新的子shell开始运行,从父shell那里export出来的变量是可见的.
这个变量被修改来存放其他名字,但是在父shell中放置变量的值还是一样的.
3.
2.
4.
保留保留保留保留变量变量变量变量3.
2.
5.
特殊参数特殊参数特殊参数特殊参数3.
2.
6.
脚本通过变量循环脚本通过变量循环脚本通过变量循环脚本通过变量循环除了使脚本变得更加易读,变量也会使你更加快速的在另外一个环境中应用一个脚本或者其他的目的.
考虑下面的例子,一个非常简单的脚本把franky的主目录备份到远程服务器上.
首先,如果每次需要的时候你都手动命名文件和目录很可能造成错误.
另外,假设franky向把这个脚本给carol,在carol能使用脚本备份她的主目录之前需要做一些编辑.
同样如果franky想使用这个脚本来备份其他目录.
为了简单的再循环,使所有的文件,目录,用户名,服务器名字等变量.
因此,你只需要编辑一次值,而不需要在整个脚本中检查哪里需要出现参数.
以下是一个例子:.
.
.
.
大目录和低带宽以上是个大家都能理解的例子,使用一个小目录和一个在相同子网的主机.
根据你的带宽,目录的大小和远程服务器的,使用这种机制来备份可能会花费很多时间.
对更大的目录和更低的带宽,使用rsync来保证目录之间保持同步.
3.
3.
引用字符引用字符引用字符引用字符3.
3.
1.
为何.
.
为何.
.
为何.
.
为何.
.
3.
3.
2.
转义字符转义字符转义字符转义字符3.
3.
3.
单引用单引用单引用单引用Bash新手指南35/913.
3.
4.
双引用双引用双引用双引用3.
3.
5.
ANSIC引用引用引用引用3.
3.
6.
Locales.
463.
4.
Shell扩展扩展扩展扩展3.
4.
1.
概要概要概要概要3.
4.
2.
大括号表达式大括号表达式大括号表达式大括号表达式3.
4.
3.
波浪表达式波浪表达式波浪表达式波浪表达式3.
4.
4.
Shell参数和变量扩展参数和变量扩展参数和变量扩展参数和变量扩展3.
4.
5.
命令替换命令替换命令替换命令替换3.
4.
6.
算术表达式算术表达式算术表达式算术表达式3.
4.
7.
替换的处理替换的处理替换的处理替换的处理3.
4.
8.
Wordsplitting3.
4.
9.
文件名扩展文件名扩展文件名扩展文件名扩展3.
5.
别名别名别名别名3.
5.
1.
什么是别名什么是别名什么是别名什么是别名3.
5.
2.
建立和消除别名建立和消除别名建立和消除别名建立和消除别名3.
6.
更多更多更多更多Bash选项选项选项选项3.
6.
1.
显示显示显示显示选项选项选项选项3.
6.
2.
改变选项改变选项改变选项改变选项3.
7.
总结总结总结总结3.
8.
练习练习练习练习Bash新手指南36/91第四章第四章第四章第四章正则表达式正则表达式正则表达式正则表达式本章我们讨论:使用正则表达式正则表达式统配符文件和输出中的找寻模板Bash中字符的范围和分类4.
1.
正则表达式正则表达式正则表达式正则表达式4.
1.
1.
什么是正则表达式什么是正则表达式什么是正则表达式什么是正则表达式4.
1.
2.
正则表达式正则表达式正则表达式正则表达式metacharacters4.
1.
3.
Basicversus扩展扩展扩展扩展正则表达式正则表达式正则表达式正则表达式4.
2.
使用使用使用使用Grep的例子的例子的例子的例子4.
2.
1.
什么是什么是什么是什么是Grepgrep以行为单位搜索那些包含给出模板列表的输入文件.
当在一行中找到匹配,默认把该行拷贝到默认输出,或者其他你以选项要求的任何种类的输出.
虽然grep力图做到在文字上的匹配,不考虑内存因素的话它对输入行的长度没有限制,而且它能匹配一行中的任何字符.
如果输入文件的最后一个字节不是换行符的话,grep会自动加上一个.
既然换行符也是模板列表的分隔符,那样就没有办法来从字面上匹配换行符.

一些例子:cathy~>greproot/etc/passwdroot:x:0:0:root:/root:/bin/bashoperator:x:11:0:operator:/root:/sbin/nologincathy~>grepnroot/etc/passwd1:root:x:0:0:root:/root:/bin/bash12:operator:x:11:0:operator:/root:/sbin/nologincathy~>grepvbash/etc/passwd|grepvnologinsync:x:5:0:sync:/sbin:/bin/syncshutdown:x:6:0:shutdown:/sbin:/sbin/shutdownhalt:x:7:0:halt:/sbin:/sbin/haltnews:x:9:13:news:/var/spool/news:Bash新手指南37/91mailnull:x:47:47::/var/spool/mqueue:/dev/nullxfs:x:43:43:XFontServer:/etc/X11/fs:/bin/falserpc:x:32:32:PortmapperRPCuser:/:/bin/falsenscd:x:28:28:NSCDDaemon:/:/bin/falsenamed:x:25:25:Named:/var/named:/bin/falsesquid:x:23:23::/var/spool/squid:/dev/nullldap:x:55:55:LDAPUser:/var/lib/ldap:/bin/falseapache:x:48:48:Apache:/var/www:/bin/falsecathy~>grepcfalse/etc/passwd7cathy~>grepips~/.
bash*|grepvhistory/home/cathy/.
bashrc:PS1="\[\033[1;44m\]$USERisin\w\[\033[0m\]"第一个例子,用户cathy把/etc/passwd里面包含root字符串的行显示出来.
然后显示了包含所搜索字符的行号.
第三个命令她检查了哪个用户没有使用bash,但是使用nologinshell的账户不显示出来.
然后他计算了哪些错误使用/bin/false作为shell的账号数量.
最后的命令显示了在她主目录中包含~/.
bash的所有文件.
排除了包含history,以致于也排除了可能包含相同字符串的~/.
bash_history文件.
现在让我们来看看grep用正则表达式还能干什么4.
2.
2.
Grep与正则表达式与正则表达式与正则表达式与正则表达式如果你不是在使用Linux我们在这些例子中使用支持扩展正则表达式的GNUgrep.
GNUgrep在Linux系统里是默认的.
如果你在有所有权的系统上工作,那么请使用-V选项来检查你在使用哪个版本的grep.
GNUgrep也可以从这里下载:http://gnu.
org/directory/4.
2.
2.
1.
锚定行和字锚定行和字锚定行和字锚定行和字从先前的例子中,我们只想显示那些使用字符串root开头的行:cathy~>grep^root/etc/passwdroot:x:0:0:root:/root:/bin/bash如果我们想看哪个账号什么shell都没有分配,我们搜索行结束符":":cathy~>grep:$/etc/passwdnews:x:9:13:news:/var/spool/news:要检查PATH是否在~/.
bashrc中,首先选择"export"然后搜索以字符串"PATH"开始的行,这样就不会搜索到MANPATH或者其他可能的路径了:cathy~>grepexport~/.
bashrc|grep'\匹配词的结尾.
Bash新手指南38/91如果你想找字符串是一个单独的单词(用空格括起来的).
最好使用-w,就像在这个例子里我们显示了root分区的信息.
cathy~>grepw//etc/fstabLABEL=//ext3defaults11如果这个选项没有使用,将会显示文件系统的表里的所有的行.
4.
2.
2.
2.
字符族字符族字符族字符族括号表达式是一个用[]括起来的字符列表.
他匹配任何在列表里的单独字符;如果列表的第一个字符是"^",那么它就匹配所有不在列表中的文件.
比如,正则表达式[0123456789]匹配任何单独的数字.
在括号表达式中,一个范围表达式有2个用-隔开的字符组成.
它匹配在这2个字符之间同类的任何单独字符,包括那2个字符.
使用本地的比较顺序和字符集.
比如,再默认的C现场,"[a-d]"等于"[abcd]".
许多本地以字典的顺序排列字符.
这样的情况下"[a-d]"通常不等于"[abcd]",可能等于"[aAbBcCdD]",比如.
为得到括号表达式的传统的解释,你可以把环境变量LC_ALL设置成"C"来使用C现场.
最后,某几个已经命名的字符族已经预先定义在括号表达式了.
请查阅grep的帮助页面以得到更多关于预先定义表达式的信息.
cathy~>grep[yf]/etc/groupsys:x:3:root,bin,admtty:x:5:mail:x:12:mail,postfixftp:x:50:nobody:x:99:floppy:x:19:xfs:x:43:nfsnobody:x:65534:postfix:x:89:cathy~>ls*[19].
xmlapp1.
xmlchap1.
xmlchap2.
xmlchap3.
xmlchap4.
xml在这个例子中,所有包含"y"或者"f"的行最先显示,后面是一个例子如何使用指定范围使用ls.
4.
2.
2.
3.
通配符通配符通配符通配符使用".
"来匹配单个字符.
如果你想得到一个以"c"开头,"h"结尾的5个字符的英语字典单词,(解决猜字游戏的好办法):cathy~>grep'\'/usr/share/dict/wordscatchclashclothcoachcouchBash新手指南39/91coughcrashcrush如果你想显示.
字符,使用-F选项.
要匹配多个字符,使用*,这个例子从系统的字典里面选择所有"c"开头和"h"结尾的单词.

cathy~>grep'\'/usr/share/dict/wordscaliphcashcatchcheeseclothcheetahoutputomitted如果你想在文件或者输出里寻找*,使用-F选项.
cathy~>grep*/etc/profilecathy~>grepF'*'/etc/profileforiin/etc/profile.
d/*.
sh;do4.
3.
模式匹配使用模式匹配使用模式匹配使用模式匹配使用Bash特性特性特性特性4.
3.
1.
字符范围字符范围字符范围字符范围从grep和正则表达式出发,shell里有很多无序使用外部程序就可以直接使用的匹配模板.
就和你已经知道的一样,*和匹配任何单个字符,下面分别引用这些特殊字符来匹配他们的字面值:cathy~>touch"*"cathy~>ls"*"*你也可以使用方括号来匹配任何enclosedcharacterorrangeofcharacters,如果字符被-分隔,一个例子cathy~>lsld[acxz]*drwxrxrx2cathycathy4096Jul202002appdefaults/drwxrwxrx4cathycathy4096May252002arabic/drwxrwxrx2cathycathy4096Mar418:30bin/drwxrxrx7cathycathy4096Sep22001crossover/drwxrwxrx3cathycathy4096Mar222002xml/列出了cathy主目录里的所有以a,b,c,x,y,z开头的文件.
4.
3.
2.
字符字符字符字符classesBash新手指南40/914.
4.
总结总结总结总结4.
5.
练习练习练习练习第五章第五章第五章第五章GNUSED流编辑器流编辑器流编辑器流编辑器本章结束你会了解到以下话题什么是sedsed的交互使用正则表达式和流编辑在脚本中使用sed命令这仅仅是一个介绍这些说明远不够完整,不能够作为如何使用sed的手册.
本章只含有为了在下一章展示一些更为有趣的话题,而且因为每个强力用户应该掌握一些基本的知识来使用这个编辑器完成些工作.

5.
1.
介绍介绍介绍介绍5.
1.
1.
什么是什么是什么是什么是sed流编辑器是用来从文件读取文本或者从管道实现基本的变化.
结果送到标准输出.
sed命令的语法不指定输出文件,但是结果可以通过使用输出重定向来写入到文件中.
编辑器并不改变原来的文件.
sed个其它编辑器比如vi和ed的区别在于它能够过滤来自管道的输入.
在编辑器运行的时候你不要去干涉它;所以sed常常被称作批编辑器.
此特性允许你在脚本中使用编辑命令,极大的方便了重复性编辑任务.
当面对文件中大量的文本替换的时候,sed将是一个极大的帮助.
5.
1.
2.
sed命令命令命令命令sed程序可以通过使用正则表达式来实现文本的模板替换和删除,就和使用grep一样,见4.
2节.
编辑命令和vi编辑器的命令很相近.
5.
2.
交互编辑交互编辑交互编辑交互编辑5.
2.
1.
打印包含打印包含打印包含打印包含pattern的行的行的行的行Bash新手指南41/91你可以用grep做不少事情,但是你不能用它来"查找和替换"这是我们的文本文件例子:sandy~>catnexample1Thisisthefirstlineofanexampletext.
2Itisatextwitherors.
3Lotsoferors.
4Somucherors,alltheseerorsaremakingmesick.
5Thisisalinenotcontaininganyerrors.
6Thisisthelastline.
sandy~>我们象让sed找到所有"erors"的行,我们使用p来得到结果.
sandy~>sed'/erors/p'exampleThisisthefirstlineofanexampletext.
Itisatextwitherors.
Itisatextwitherors.
Lotsoferors.
Lotsoferors.
Somucherors,alltheseerorsaremakingmesick.
Somucherors,alltheseerorsaremakingmesick.
Thisisalinenotcontaininganyerrors.
Thisisthelastline.
就像你看到的,sed打印出了整个文件,但是包含搜索字符串的行被打印了2次.
这不是我们想要的.
为了只符合要求的行,使用-n选项.
sandy~>sedn'/erors/p'exampleItisatextwitherors.
Lotsoferors.
Somucherors,alltheseerorsaremakingmesick.
sandy~>5.
2.
2.
删除包含删除包含删除包含删除包含pattern的输入行的输入行的输入行的输入行我们使用同样的文本文件作为例子.
现在我们只想看到那些不包含所要搜索字符串的行:sandy~>sed'/erors/d'exampleThisisthefirstlineofanexampletext.
Thisisalinenotcontaininganyerrors.
Thisisthelastline.
sandy~>d命令使得被排除的行不显示出来.
匹配以第一个模板开头的和第二个模板结尾的行应该写成这样:Bash新手指南42/91sandy~>sedn'/^This.
*errors.
$/p'exampleThisisalinenotcontaininganyerrors.
sandy~>5.
2.
3.
行的范围行的范围行的范围行的范围这次我们想单独列出包含错误的行.
在例子中它们是第2-4行.
使用d命令来指定地址的范围:sandy~>sed'2,4d'exampleThisisthefirstlineofanexampletext.
Thisisalinenotcontaininganyerrors.
Thisisthelastline.
sandy~>要打印出文件中以特定行开头的直到最后一行的,使用如下的命令:sandy~>sed'3,$d'exampleThisisthefirstlineofanexampletext.
Itisatextwitherors.
sandy~>这个例子中只打印出例子里的头两行.
下面的命令打印出饱含"atext"的第一次,直到下个包含"aline"的一行:sandy~>sedn'/atext/,/This/p'exampleItisatextwitherors.
Lotsoferors.
Somucherors,alltheseerorsaremakingmesick.
Thisisalinenotcontaininganyerrors.
sandy~>5.
2.
4.
用用用用sed查找替换查找替换查找替换查找替换在例子中,我们会搜索和替换错误来代替只选择(或者不选择)包含需要查找字符串的行.

sandy~>sed's/erors/errors/'exampleThisisthefirstlineofanexampletext.
Itisatextwitherrors.
Lotsoferrors.
Somucherrors,alltheseerorsaremakingmesick.
Thisisalinenotcontaininganyerrors.
Thisisthelastline.
sandy~>就像你看到的,这并不完全就是我们想要得:在第4行,只有第一个待搜索字符串被替换了,左面还有一个"eror"没有被替换.
使用g命令来使sed检查所有的行而不在搜索到第一个匹配Bash新手指南43/91字符串后就停止:sandy~>sed's/erors/errors/g'exampleThisisthefirstlineofanexampletext.
Itisatextwitherrors.
Lotsoferrors.
Somucherrors,alltheseerrorsaremakingmesick.
Thisisalinenotcontaininganyerrors.
Thisisthelastline.
sandy~>要在文件的每一行开始处插入一个字符串,比如引用:sandy~>sed's/^/>/'example>Thisisthefirstlineofanexampletext.
>Itisatextwitherors.
>Lotsoferors.
>Somucherors,alltheseerorsaremakingmesick.
>Thisisalinenotcontaininganyerrors.
>Thisisthelastline.
sandy~>在每行的尾部插入字符串:sandy~>sed's/$/EOL/'exampleThisisthefirstlineofanexampletext.
EOLItisatextwitherors.
EOLLotsoferors.
EOLSomucherors,alltheseerorsaremakingmesick.
EOLThisisalinenotcontaininganyerrors.
EOLThisisthelastline.
EOLsandy~>多个查找替换命令用单独选项-e来隔开:sandy~>sede's/erors/errors/g'e's/last/final/g'exampleThisisthefirstlineofanexampletext.
Itisatextwitherrors.
Lotsoferrors.
Somucherrors,alltheseerrorsaremakingmesick.
Thisisalinenotcontaininganyerrors.
Thisisthefinalline.
sandy~>记住sed默认把结果送到标准输出,比如你的终端窗口.
如果你想把输出保存到文件,使用重定向:sedoption'some/expression'file_to_process>sed_output_in_a_fileBash新手指南44/91更多例子大量的sed例子可以在你机器的启动文件里找到,通常在/etc/init.
d或者/etc/rc.
d/init.
d.
切换到包含初始化脚本的目录中然后输入日下命令.
grepsed*5.
3.
非交互编辑非交互编辑非交互编辑非交互编辑5.
3.
1.
从文件读取从文件读取从文件读取从文件读取sed命令命令命令命令从文件读取sed命令多个sed命令可以一起放到一个文件中,用-f选项来执行.
当建立了一个这样的文件,请确保:每行的末尾没有多余的空格.
不能使用引用当进入文本来添加和替换的时候,除了最后行已为的所有行都要以反斜扛结尾.

5.
3.
2.
写写写写输出输出输出输出文件文件文件文件当使用重定向符号>的时候,写输出就完成了.
这是一个例子脚本,用来从纯文本文件建立非常简单的HTML文件.
sandy~>catscript.
sed1i\\sedgeneratedhtml\\$a\\\sandy~>cattxt2html.
sh#!
/bin/bash#ThisisasimplescriptthatyoucanuseforconvertingtextintoHTML.
#Firstwetakeoutallnewlinecharacters,sothattheappendingonlyhappens#once,thenwereplacethenewlines.
echo"converting$1.
.
.
"SCRIPT="/home/sandy/scripts/script.
sed"NAME="$1"Bash新手指南45/91TEMPFILE="/var/tmp/sed.
$PID.
tmp"sed"s/\n/^M/"$1|sedf$SCRIPT|sed"s/^M/\n/">$TEMPFILEmv$TEMPFILE$NAMEecho"done.
"sandy~>$1把第一个参数送到命令中,这个例子中它是要转换的文件的名字:sandy~>cattestline1line2line3更多的位置参数请参见第七章.
sandy~>txt2html.
shtestconvertingtest.
.
.
done.
sandy~>cattestsedgeneratedhtmlline1line2line3sandy~>这个并不是真的,这个例子,只是为了证明sed的能力,一个更好的解决这个问题的办法请参见6.
3,它使用awk的BEGIN和END结构.
Easysed高级编辑器,支持语法的高亮来识别sed语法.
如果你忘记反斜杠之类的它将提供很大的帮助.
5.
4.
总结总结总结总结sed流变及其是一个强大的命令行工具,能处理数据流:能从管道读取输入行.
这使得它社和非交互使用.
sed编辑器使用类似vi的命令且支持正则表达式.
sed工具可以从命令行或者脚本文件读取命令.
他经常用来实现查找和替换的包含特定字符串的行的工作.
Bash新手指南46/915.
5.
练习练习练习练习第六章第六章第六章第六章GNUAWK编程语言编程语言编程语言编程语言本章我们会讨论什么是gawk在命令行中使用gawk命令怎么使用gawk来格式化文本gawk怎么使用则正则表达式脚本中的gawkgawk和变量把它变得更有趣味就像sed一样,整本书写了多个版本的awk.
这个介绍远还不够完整,且只是为了能够理解在后面章节中的例子.
要得到更多的信息,最好是从GNUawk的随附文档开始.
.
.
6.
1.
gawk上路上路上路上路6.
1.
1.
什么是什么是什么是什么是gawkgawk是通常在UNIX系统下使用的另外一个流行的流编辑器awk的GNU版本.
虽然awk程序常常只是一个gawk的连接,但是我们还是称作它为awk.
awk的最基本的作用是搜索含有1个或者多个模板的文件中的行或者其他文本块.
当一行符合搜索的模板,在该行就会实现指定的动作.
在awk中的程序和许多其他语言中的程序是不一样的,因为awk程序是:你先描述你想处理的数据,然后当找到它们的时候怎么处理.
许多其他的语言是"过程的".
你需要具体的描述程序该采取的措施.
当使用过程化的语言时,通常更难清楚地描述你需要处理的数据.
正因为如此,awk程序经常能清爽地读写.
6.
1.
2.
Gawk命令命令命令命令当你运行gawk的时候,你指定一个awk程序来通知awk该如何做.
程序由几个规则组成.
(也可能包含函数定义,循环,条件和其他程序结构,高级特性等一系列我们已经遗忘的东西.

)每个规则指定了搜索的模板和在搜索到一个模板后执行的动作.
有几种运行awk的方法.
如果程序很短,最方便的是在命令行运行它:awkPROGRAMinputfile(s)Bash新手指南47/91在已经完成的多个改变,通常在多个文件,很方便把awk命令放到脚本当中,读起来像这样:awk-fPROGRAMFILEinputfile(s)6.
2.
打印程序打印程序打印程序打印程序6.
2.
1.
打印选择的打印选择的打印选择的打印选择的域域域域awk中的print命令把输入文件中选择的数据输出.
当awk读取文件的一行,根据制定的域分隔符把行分开,FS,awk的一个环境变量.
它被预先定义为一个或者多个空格或者制表符.
变量$1$2$3.
.
$n把输入行的第一第二第三直到最后一个域保存起来.
变量$0把整行的值保存起来.
在下面的图片描述中,我们看到df命令输出有6栏.
图6-1.
awk中的域6.
2.
2.
格式化块格式化块格式化块格式化块没有格式化,只使用输出分隔符的话看上去比较破,插入几个制表符和指示输出的标记会使它变得漂亮很多:kelly@octarine~/test>lsldh*|grepvtotal|\awk'{print"Sizeis"$5"bytesfor"$9}'Sizeis160bytesfororigSizeis121bytesforscript.
sedSizeis120bytesfortemp_fileSizeis126bytesfortestBash新手指南48/91Sizeis120bytesfortwolinesSizeis441bytesfortxt2html.
shkelly@octarine~/test>注意反斜杠的用法,让shell不把它翻译成分隔命令而使其在下一行继续很长的输入.
虽然命令行的输入实际上是没有长度限制的,但是你的显示器不是,打印的纸当然也不是.
使用反斜杠也允许拷贝和粘贴以上行道一个终端窗口.
ls的-h选项用来支持把大文件的字节数转换成更容易读的格式.
当把目录作为参数的时候长列表的输出显示目录中快的总数.
这行对我们并没有什么用处,所以我们加上一个*.
同样的原因我们同样加上-d选项,万一*对一个目录展开.
在这个例子中的反斜杠提示了一行的延长.
见3.
2节.
甚至在反序中你也能取出任何栏的的数字.
下面的例子证明了最苛刻的区分.

kelly@octarine~>dfh|sortrnk5|head3|\awk'{print"Partition"$6"\t:"$5"full!
"}'Partition/var:86%full!
Partition/usr:85%full!
Partition/home:70%full!
kelly@octarine~>下表给出了特殊格式化字符的总揽.
.
.
.
.
引用,$和其他元字符应该使用反斜杠来进行转义.
6.
2.
3.
打印命令和正则表达式打印命令和正则表达式打印命令和正则表达式打印命令和正则表达式用斜杠把正则表达式包含起来可以当作一个pattern.
然后正则表达式测试整个文本的每条记录.
语法如下:.
.
.
下面的例子现实了只有本地磁盘设备的信息,网络文件系统没有显示:kellyisin~>dfh|awk'/dev\/hd/{print$6"\t:"$5}'/:46%/boot:10%/opt:84%/usr:97%/var:73%/.
vol1:8%kellyisin~>Bash新手指南49/91斜杠也需要转义,因为对于awk它们有着特殊的含义.
下面的另外一个例子是我们在/etc目录搜索以".
conf"结尾和"a"或者"x"开头的文件,使用扩展的正则表达式.
kellyisin/etc>lsl|awk'/\这个例子说明了在正则表达式中.
的特殊意义.
第一个表明了我们想要搜索在第一个搜索字符串之后的任何字符,第二个因为是要查找字符串的一部分所以被转义了(文件名的结束).
6.
2.
4.
特殊的特殊的特殊的特殊的pattern为了在输出之前加上注释,使用BEGIN语句.
kellyisin/etc>lsl|\awk'BEGIN{print"Filesfound:\n"}/\加上END语句能插入文本在整个输入被处理之后.
kellyisin/etc>lsl|\awk'/\6.
2.
5.
Gawk脚本脚本脚本脚本往往命令都有点长,你可能想把他们放到脚本中,来重用它.
一个awk脚本包含定义pattern和动作的awk语句.
作为一个说明,我们将建立一个报告来显示占用率最高的分区,请看6.
2.
2.
节Bash新手指南50/91kellyisin~>catdiskrep.
awkBEGIN{print"***WARNINGWARNINGWARNING***"}/\dfh|awkfdiskrep.
awk***WARNINGWARNINGWARNING***Partition/usr:97%full!
***GivemoneyfornewdisksURGENTLY!
***kellyisin~>awk先打印一个开始信息,然后格式化所有包含一个8或者9开头的词的行,然后后接一个数字和百分符号,然后加入结束信息.
语法高亮Awk是一个编程语言.
他的语法能被大多数能对其他语言比如c,bash,HTML进行语法高亮编辑器所识别.
6.
3.
Gawk变量变量变量变量既然awk处理输入文件,他使用几个变量.
一些是可以编辑的,一些是只读的.
6.
3.
1.
输入块的分隔符输入块的分隔符输入块的分隔符输入块的分隔符域分隔符,既不是一个单独的字符也不是一个普通的表达式,是控制awk把一个输入分割成几个域.
输入纪录按分割定义进行字符顺序扫描;域就是在相符的那些文字中间的那部分.

域分隔符代表内建的变量FS,注意POSIX标准的shell使用的变量IFS和他是有一些区别的.
域分隔符变量的值可以在awk程序中用赋值操作符=来改变.
通常最好的执行时间是一开始也就是还没有处理任何输入的时候,因此第一个记录就被随合适的分隔符一起读取.
要这么做,清使用特殊的BEGINpattern以下的例子,我们编制了一条命令来显示系统里的所有用户及其描述:kellyisin~>awk'BEGIN{FS=print$1"\t"$5}'/etc/passwdoutputomittedkellyKellySmithfrankyFrankyB.
eddyEddyWhitewillyWilliamBlackcathyCatherinetheGreatsandySandyLiWongkellyisin~>Bash新手指南51/91在一个awk脚本中,他看起来像这样:kellyisin~>catprintnames.
awkBEGIN{FS=":"}{print$1"\t"$5}kellyisin~>awkfprintnames.
awk/etc/passwdoutputomitted小心地选择输入分隔域来防止出现问题.
一个例子来说明这个:说你需要输入想这样的行的形式:"SandyL.
Wong,64ZooSt.
,Antwerp,2000X"你这样写了一个打印出记录中人的名字的命令行或者是脚本:awk'BEGIN{FS=print$1,$2,$3}'inputfile但是可能一个人有PhD,而且可能写成这样:"SandyL.
Wong,PhD,64ZooSt.
,Antwerp,2000X"你的awk会给出错误的输出.
需要的话,使用额外的一个awk或者sed来统一数据输出的格式.
默认的输入分隔符是一个或多个空格和制表符.
6.
3.
2.
输出的分隔符输出的分隔符输出的分隔符输出的分隔符6.
3.
2.
1.
输出域分隔符在输出中域通常被空格分隔.
当你对print命令使用正确的语法且字段用逗号分隔时,这将很明显的:kelly@octarine~/test>cattestrecord1data1record2data2kelly@octarine~/test>awk'{print$1$2}'testrecord1data1record2data2kelly@octarine~/test>awk'{print$1,$2}'testrecord1data1record2data2kelly@octarine~/test>如果你不输入逗号,print将把输出的项目全部当成一个字段,因此省略默认输出分隔符--OFS的使用.
6.
3.
2.
2.
输出记录分隔符Bash新手指南52/91整个print语句的输出叫做输出记录.
每个在输出记录里的print命令的结果,输出一个叫做输出记录分隔符ORS的字符串.
这个变量的默认值是"\n",一个换行符.
因此,每个print语句生成一个单独的行.
要改变输出域和记录的,只要给OFS和ORS赋新的值:kelly@octarine~/test>awk'BEGIN{OFS=";";ORS="\n>\n"}\{print$1,$2}'testrecord1;data1>record2;data2>kelly@octarine~/test>如果ORS的值不包含换行,那么程序中的输出就会输出成一个单独行.
6.
3.
3.
记录的数量记录的数量记录的数量记录的数量内建的NR包含了处理过的记录的数量.
在读入一个新的输入行之后他会自行增加一次.
你可以用它来计算记录的总数,或者在每个输出记录中:kelly@octarine~/test>catprocessed.
awkBEGIN{OFS="";ORS="\n>done\n"}{print"Recordnumber"NR":\t"$1,$2}END{print"Numberofrecordsprocessed:"NR}kelly@octarine~/test>awkfprocessed.
awktestRecordnumber1:record1data1>doneRecordnumber2:record2data2>doneNumberofrecordsprocessed:2>donekelly@octarine~/test>6.
3.
4.
用户定义用户定义用户定义用户定义变量变量变量变量除了内建的变量之外,你也可以定义自己的变量.
当awk碰到一个不存在的变量(没有事先定义的)的引用时,这个变量就被创建并且使用一个空字符串进行赋值.
对于后来所有的引用,就是该变量最后被赋予的那个值.
变量可以是一个字符串或者一个数字.
输入域的内容也可以被赋予变量.
值可以直接用=来赋值,或者你可以使用现有变量的值和其他操作符组合.

kelly@octarine~>catrevenuesBash新手指南53/912002100920021013consultancyBigComp25002002101520021020trainingEduComp20002002111220021123appdevSmartComp100002002120420021215trainingEduComp5000kelly@octarine~>cattotal.
awk{total=total+$5}{print"Sendbillfor"$5"dollarto"$4}END{printnTotalrevenue:"total}kelly@octarine~>awkftotal.
awktestSendbillfor2500dollartoBigCompSendbillfor2000dollartoEduCompSendbillfor10000dollartoSmartCompSendbillfor5000dollartoEduCompTotalrevenue:19500kelly@octarine~>类似于C的简写VAR+=value也是可以接受的.
6.
3.
5.
更多例子更多例子更多例子更多例子当我们使用awk脚本时,5.
3.
2.
节的例子会变得更加容易.
kelly@octarine~/html>catmakehtmlfromtext.
awkBEGIN{print"\nAwkgeneratedHTML\n\{print$0}END{print"\n\n"}而且当用awk来替代sed受,命令也变得更加直截了当.
kelly@octarine~/html>awkfmakehtmlfromtext.
awktestfile>file.
html在你系统上的awk例子.
我们再次回到包含你系统启动脚本的目录.
输入一个和以下相似的命令来查看更多awk命令的使用方法:grepawk/etc/init.
d/*6.
3.
6.
printf程序程序程序程序为了更精确的控制print提供的正常输出格式,可以使用printf.
pringtf命令可以用来指明每个项目使用的域的宽度,同时也有用于数字的多种格式选择.
这一切只要增加一个字符串,叫做格式字符串,控制怎样和那里来打印那些项目.
Bash新手指南54/91语法也和C语言的printf语句相似;请察看你的C介绍手册.
gawk信息页面包含完整的解释.
6.
4.
总结总结总结总结gawk工具解释特殊目的的编程语言,处理简单的数据重新格式化的工作,只需要几行代码.
他是通常UNIXawk命令的免费版本.
这个工具从输入数据读取行且能够方便的识别.
print是最普通的来过滤和格式化定义的域的程序.
闲置的变量可以直接声明也允许在处理输入流的同时进行简单的计算求和,统计和其他运算.
变量和命令可以放到awk脚本来进行后台处理.
6.
5.
练习练习练习练习Bash新手指南55/91第七章第七章第七章第七章条件语句条件语句条件语句条件语句本章我们会讨论在Bash脚本中使用条件,包含以下几个话题:if语句使用命令的退出状态比较和测试输入和文件if/then/else结构if/then/elif/else结构使用和测试位置参数嵌套if语句布尔表达式使用case语句7.
1.
介绍介绍介绍介绍if7.
1.
1.
概要概要概要概要有时候你需要指定shell脚本中的依靠命令的成功与否来实施不同过程的行为.
if结构允许你来指定这样的条件.
最精简的if命令的语法是:if测试命令;then后继命令;fi测试命令执行后且它的返回状态是0,那么后继命令就执行.
返回状态是最后一个命令的退出状态,或者没有条件是真的话为0.
测试命令经常包含数字或者字符串比较测试,但它也可以是任何成功返回状态是0和失败返回其他状态的命令.
一元表达式经常用来检验文件的状态.
如果一个主要的FILE参数是/dev/fd/N这样的形式的话,就检查文件描述符"N".
stdin,stdout和stderr和他们各自的文件描述符也可以7.
1.
1.
1.
和if使用的表达式下表包含了一个表7-1.
主表达式Primary意义[-a文件]如果文件存在为真.
[-b文件]如果文件存在而且是一个块-特殊文件为真.
[-c文件]为真如果文件存在而且是一个字-特殊文件.
Bash新手指南56/91[-d文件]为真如果文件存在而且是一个目录.
[-e文件]为真如果文件存在.
[-f文件]为真如果文件存在而且是一个普通文件.
[-g文件]为真如果文件存在而且已经设置了他的SGID位.
[-h文件]为真如果文件存在而且是一个符号连接.
[-k文件]为真如果文件存在而且他的粘住位已经设置.
[-p文件]为真如果文件存在而且是一个已经命名的管道(F如果O).
[-r文件]为真如果文件存在而且是可读的.
[-s文件]为真如果文件存在而且比零字节大.
[-tFD]为真如果文件文件描述符已经打开而且指向一个终端.
[-u文件]为真如果文件存在而且已经设置了他的SUID(setuserID)位.
[-w文件]为真如果文件为真如果文件存在而且是可写的.
[-x文件]为真如果文件存在而且是可执行的.
[-O文件]为真如果文件存在而且属于有效用户ID.
[-G文件]为真如果文件存在而且属于有效组ID.
[-L文件]为真如果文件存在而且是一个符号连接.
[-N文件]为真如果文件存在而且hasbeenmod如果iedsinceitwaslastread.
[-S文件]为真如果文件存在而且是一个socket.
[文件1-nt文件2]为真如果文件1hasbeenchangedmorerecentlythan文件2,or如果文件1存在而且文件2doesnot.
[文件1-ot文件2]为真如果文件1比文件2旧,或者文件2存在而且文件1不存在.
[文件1-ef文件2]为真如果文件1而且文件2refertothesamedevice而且inodenumbers.
[-o选项名]为真如果shell选项"选项名"开启.
[-zSTRING]为真如果"STRING"的长度是零.
[-nSTRING]或者[STRING]为真"STRING"的长度是非零值.
[STRING1==STRING2]如果两个字符串相等为真.
"="maybeusedinsteadof"=="forstrictPOSIXcompliance.
[STRING1!
=STRING2]为真如果两两个字符串不相等.
[STRING1STRING2]为真如果"STRING1"sortsafter"STRING2"lexicographicallyinthecurrentlocale.
[ARG1OPARG2]"OP"是-eq,-ne,-lt,-le,-gtor-ge其中一个.
Thesearithmeticbinaryoperatorsreturn为真如果"ARG1"isequalto,notequalto,lessthan,lessthanorequalto,greaterthan,orgreaterthanorequalto"ARG2",respectively.
"ARG1"而且"ARG2"areintegers.
表达式可以借以下操作符组合起来,listedindecreasingorderofprecedence:操作符效果[!
EXPR]如果EXPR为假则为真.
[(EXPR)]返回EXPR的值.
这样可以用来忽略正常的操作符优先级.
Bash新手指南57/91[表达式1-a表达式2]如果表达式1而且表达式2同时为真则为真.
[表达式1-o表达式2]如果表达式1或者表达式2其中之一为真则为真.
"["内建运算条件表达式使用一系列基于参数数量的规则.
更多关于这个的信息可以在Bash文档中查找.
就像if使用fi来结束一样,在条件列完之后必须用"]"来结束.
7.
1.
1.
2.
后接then语句的命令后继命令列出了跟在then语句后面可以使任何有效的UNIX命令,任何可执行的程序,任何可执行的shell脚本或者任何shell语句.
重要地记住then和fi在shell里面被认为是分开的语句.
因此,在命令行上使用的时候,他们用分号隔开.
在脚本中,if语句的不同部分通常是良好分隔的.
以下是一些简单的例子.
7.
1.
1.
3.
检查文件第一个例子检查一个文件是否存在anny~>catmsgcheck.
sh#!
/bin/bashecho"Thisscriptscheckstheexistenceofthemessagesfile.
"echo"Checking.
.
.
"if[f/var/log/messages]thenecho"/var/log/messagesexists.
"fiechoecho".
.
.
done.
"anny~>.
/msgcheck.
shThisscriptscheckstheexistenceofthemessagesfile.
Checking.
.
.
/var/log/messagesexists.
.
.
.
done.
7.
1.
1.
4.
检查shell选项加入到你的Bash配置文件中去:#Theselineswillprintamessageifthenoclobberoptionisset:if[onoclobber]thenBash新手指南58/91echo"Yourfilesareprotectedagainstaccidentaloverwritingusingredirection.
"fi环境以上的例子将在命令行输入后开始工作:anny~>if[onoclobber];thenecho;echo"yourfilesareprotectedagainstoverwriting.
";echo;fiyourfilesareprotectedagainstoverwriting.
anny~>然而,如果你使用依赖环境的测试,当你在脚本中输入相同的命令你可能得到不用的结果,因为脚本会打开一个新的预期的变量和选项可能没有自动设置的shell.
7.
1.
2.
if的简单应用的简单应用的简单应用的简单应用7.
1.
2.
1测试退出状态变量包含了之前执行命令的退出状态(最近完成的前台进程)以下的例子显示了一个简单的测试:anny~>if[$eq0]Moreinput>thenecho'Thatwasagoodjob!
'Moreinput>fiThatwasagoodjob!
anny~>以下的例子证明了测试命令可以使任何有返回和退出状态的UNIX命令,之后if再次返回零的退出状态.
anny~>if!
grep$USER/etc/passwdMoreinput>thenecho"youruseraccountisnotmanagedlocally";fiyouruseraccountisnotmanagedlocallyanny>echo$0anny>以下能得到同样的结果:anny>grep$USER/etc/passwdanny>if[$ne0];thenecho"notalocalaccount";finotalocalaccountanny>Bash新手指南59/917.
1.
2.
2.
数字的比较以下的例子是用了数值的比较:anny>num=`wclwork.
txt`anny>echo$num201anny>if["$num"gt"150"]Moreinput>thenecho;echo"you'veworkedhardenoughfortoday.
"Moreinput>echo;fiyou'veworkedhardenoughfortoday.
anny>这个脚本在每个星期天由cron来执行.
如果星期的数量一致,他就提醒你把垃圾箱清理.
#!
/bin/bash#Calculatetheweeknumberusingthedatecommand:WEEKOFFSET=$[$(date+"%V")%2]#Testifwehavearemainder.
Ifnot,thisisanevenweeksosendamessage.
#Else,donothing.
if[$WEEKOFFSETeq"0"];thenecho"Sundayevening,putoutthegarbagecans.
"|mails"Garbagecansout"your@your_domain.
7.
1.
2.
3.
字符串比较一个通过比较字符串来测试用户ID的例子:if["$(whoami)"!
='root'];thenecho"Youhavenopermissiontorun$0asnonrootuser.
"exit1;fi使用Bash,你可以缩短这样的结构.
下面是以上测试的精简结构:["$(whoami)"!
='root'echoyouareusinganonprivilegedaccount;exit1)类似于如果测试为真就执行的"&&"表达式,"||"指定了测试为假就执行.
正则表达式也可以在比较中使用:anny>gender="female"anny>if[["$gender"==f*]]Moreinput>thenecho"Pleasuretomeetyou,Madame.
";fiPleasuretomeetyou,Madame.
Bash新手指南60/91anny>真正的程序员多数程序员更喜欢使用和方括号相同作用的内建的test命令,像这样:test"$(whoami)"!
='root'&&(echoyouareusinganonprivilegedaccount;exit1)察看Bash信息页面得到更多关于"((EXPRESSION))"和"[[EXPRESSION]]"结构的模块匹配信息.
7.
2.
更多更多更多更多if的高级使用方法的高级使用方法的高级使用方法的高级使用方法7.
2.
1.
if/then/else结构结构结构结构7.
2.
1.
1.
虚构的例子这是如果一个if命令测试为真,另外一个if测试是假而采取以系列行动的例子:freddyscripts>gender="male"freddyscripts>if[["$gender"=="f*"]]Moreinput>thenecho"Pleasuretomeetyou,Madame.
"Moreinput>elseecho"Howcometheladyhasn'tgotadrinkyet"Moreinput>fiHowcometheladyhasn'tgotadrinkyetfreddyscripts>就像CONSEQUENT-COMMANDS跟在then语句后面一样,ALTERNATE-CONSEQUENT-COMMANDS跟在else后面并可以使用任何有返回状态的UNIX风格命令.
另外一个例子,从7.
1.
2.
1.
扩展开来anny~>suPassword:[root@eleganceroot]#if!
grep^$USER/etc/passwd1>/dev/null>thenecho"youruseraccountisnotmanagedlocally">elseecho"youraccountismanagedfromthelocal/etc/passwdfile">fiyouraccountismanagedfromthelocal/etc/passwdfile[root@eleganceroot]#我们切换到root账号来证明else语句的效果-root通常是一个本地账号虽然你自己的账号可能被一个特定的系统管理着,比如LDAP服务器.
Bash新手指南61/917.
2.
1.
2.
检查命令行参数除了设置完参数然后运行脚本之外,通常更好的方法是通过命令行给变量设置值.

我们使用位置参数$1,$2,.
.
.
,$N来达到此目的.
$#代表了命令行的参数数量,$0代表了脚本的名字.
图7-1使用if来测试命令行参数这里是另外一个例子,使用2个参数:anny~>catweight.
sh#!
/bin/bash#Thisscriptprintsamessageaboutyourweightifyougiveityour#weightinkilosandhightincentimeters.
weight="$1"height="$2"idealweight=$[$height110]if[$weightle$idealweight];thenecho"Youshouldeatabitmorefat.
"elseecho"Youshouldeatabitmorefruit.
"fianny~>bashxweight.
sh55169+weight=55+height=169+idealweight=59+'['55le59']'+echo'Youshouldeatabitmorefat.
'Youshouldeatabitmorefat.
Bash新手指南62/917.
2.
1.
3.
测试参数的数量以下的例子显示了怎么改变之前的脚本如果参数少于或者多余2个来打印出一条消息:anny~>catweight.
sh#!
/bin/bash#Thisscriptprintsamessageaboutyourweightifyougiveityour#weightinkilosandhightincentimeters.
if2];thenecho"Usage:$0weight_in_kiloslength_in_centimeters"exitfiweight="$1"height="$2"idealweight=$[$height110]if[$weightle$idealweight];thenecho"Youshouldeatabitmorefat.
"elseecho"Youshouldeatabitmorefruit.
"fianny~>weight.
sh70150Youshouldeatabitmorefruit.
anny~>weight.
sh7015033Usage:.
/weight.
shweight_in_kiloslength_in_centimeters第一个参数代表$1,第二个参数代表$2,以此类推,参数数量的总数存在$#中.

查阅7.
2.
5.
来得到更多打印消息的方法.
7.
2.
1.
4.
测试一个存在的文件在许多脚本当中这个测试都成功,因为如果你知道某些功能不工作那运行很多程序也是没有用的:#!
/bin/bash#Thisscriptgivesinformationaboutafile.
FILENAME="$1"echo"Propertiesfor$FILENAME:"if[f$FILENAME];thenecho"Sizeis$(lslh$FILENAME|awk'{print$5}')"echo"Typeis$(file$FILENAME|cutd":"f2)"echo"Inodenumberis$(lsi$FILENAME|cutd""f1)"Bash新手指南63/91echo"$(dfh$FILENAME|grepvMounted|awk'{print"On",$1",\whichismountedasthe",$6,"partition.
"}')"elseecho"Filedoesnotexist.
"fi注意文件是使用变量来指向的;在这个例子中它是脚本的第一个参数.
另外,当没有提供任何参数的时候,文件的存放位置通常存储在脚本开始处的变量里,他们的内容是依赖于使用的那些变量.
因此,当你想在脚本中改变文件的名字,你只要做一次.
7.
2.
2.
if/then/elif/else结构结构结构结构7.
2.
2.
1.
概要这是if语句的完全形式:ifTEST-COMMANDS;thenCONSEQUENT-COMMANDS;elifMORE-TEST-COMMANDS;thenMORE-CONSEQUENT-COMMANDS;elseALTERNATE-CONSEQUENT-COMMANDS;fiTEST-COMMANDS执行后,如果他的返回状态是零,那么就执行CONSEQUENT-COMMANDS.
如果TEST-COMMANDS返回一个非零值,每个elif依次执行,相应的MORE-CONSEQUENT-COMMANDS就执行,然后命令结束.
7.
2.
2.
2.
例子这是一个你可以把它放到crontab来每天执行的例子:anny/etc/cron.
daily>catdisktest.
sh#!
/bin/bash#Thisscriptdoesaverysimpletestforcheckingdiskspace.
space=`dfh|awk'{print$5}'|grep%|grepvUse|sortn|tail1|cutd"%"f1`alertvalue="80"if["$space"ge"$alertvalue"];thenecho"Atleastoneofmydisksisnearlyfull!
"|mails"dailydiskcheck"rootelseecho"Diskspacenormal"|mails"dailydiskcheck"rootfi7.
2.
3.
if嵌套语句嵌套语句嵌套语句嵌套语句Bash新手指南64/91在if语句里面,你可以使用另外一个if语句.
只要你能逻辑管理你就可以使用多层嵌套.
以下是一个测试闰年的例子:anny~/testdir>cattestleap.
sh#!
/bin/bash#Thisscriptwilltestifwe'reinaleapyearornot.
year=`date+%Y`if[$[$year%400]eq"0"];thenecho"Thisisaleapyear.
Februaryhas29days.
"elif[$[$year%4]eq0];thenif[$[$year%100]ne0];thenecho"Thisisaleapyear,Februaryhas29days.
"elseecho"Thisisnotaleapyear.
Februaryhas28days.
"fielseecho"Thisisnotaleapyear.
Februaryhas28days.
"fianny~/testdir>dateTueJan1420:37:55CET2003anny~/testdir>testleap.
shThisisnotaleapyear.
7.
2.
4.
布尔操作布尔操作布尔操作布尔操作以上的脚本可以用布尔操作符"AND"(&&)和"OR"(||)来缩短.
图7-2.
使用布尔操作符的例子我们使用双括号来测试一个数学表达式,见3.
4.
6.
节.
和使用let语句是一样的.
如果使用类似Bash新手指南65/91$[$year%4],可能你会对方括号的使用感到迷惑,在其他一些编辑器中,gvim是根据文件格式来进行色彩显示的其中之一;这些编辑器在发现代码中的错误时候非常有用.
7.
2.
5.
使用使用使用使用exit语句和语句和语句和语句和if我们已经在7.
2.
1.
3.
节简要的看到了exit语句.
他使整个脚本中止运行.
最常使用于判断从用户那里清酒的输入是否正确,比如一条语句没有成功运行或者某些其他错误发生.

exit语句可以带一个可选参数.
参数是一个整数,代表存贮在$中的返回给父进程的退出状态码.
0参数意味着脚本成功运行完毕.
程序员会用其他值来给父进程传递消息,所以根据子进程的成功或者失败,父进程采取不同的动作.
如果没有参数给exit语句,父shell使用$现存值.
下面是一个和penguin.
sh脚本相似的例子,会对feed.
sh传回一个退出状态:anny~/testdir>catpenguin.
sh#!
/bin/bash#ThisscriptletsyoupresentdifferentmenustoTux.
Hewillonlybehappy#whengivenafish.
We'vealsoaddedadolphinand(presumably)acamel.
if["$menu"=="fish"];thenif["$animal"=="penguin"];thenecho"Hmmmmmmfish.
.
.
Tuxhappy!
"elif["$animal"=="dolphin"];thenecho"Pweetpeettreetppeterdepweet!
"elseecho"*prrrrrrrt*"fielseif["$animal"=="penguin"];thenecho"Tuxdon'tlikethat.
Tuxwantsfish!
"exit1elif["$animal"=="dolphin"];thenecho"Pweepwishpeeterdepweet!
"exit2elseecho"Willyoureadthissign!
"exit3fifiBash新手指南66/91这个脚本被下面那个调用,anny~/testdir>catfeed.
sh#!
/bin/bash#Thisscriptactsupontheexitstatusgivenbypenguin.
shexportmenu="$1"exportanimal="$2"feed="/nethome/anny/testdir/penguin.
sh"$feed$menu$animalcase$in1)echo"Guard:You'dbettergive'mafish,lesstheygetviolent.
.
.
";;2)echo"Guard:It'sbecauseofpeoplelikeyouthattheyareleavingearthallthetime.
.
.
";;3)echo"Guard:BuythefoodthattheZooprovidesfortheanimals,you***,howdoyouthinkwesurvive";;*)echo"Guard:Don'tforgettheguide!
";;esacanny~/testdir>.
/feed.
shapplepenguinTuxdon'tlikethat.
Tuxwantsfish!
Guard:You'dbettergive'mafish,lesstheygetviolent.
.
.
就像你看到的,退出状态码可以自由选择.
退出命令通常有一系列预定义码;请见程序员手册得到每个命令的更多信息.
7.
3.
使用使用使用使用case语句语句语句语句7.
3.
1.
简单的条件简单的条件简单的条件简单的条件嵌套if语句可能比较美观,但是只要你面临可能采取的一系列的不同动作时,你可能会迷惑.

要处理复杂条件时,使用case语句:caseEXPRESSIONinCASE1)COMMAND-LIST;;CASE2)COMMAND-LIST;;.
.
.
CASEN)COMMAND-LIST;;esac每个分支是一个符合pattern,在COMMAND-LIST中符合的的命令就执行.
"|"符号用来分割多Bash新手指南67/91个pattern,"("操作符中断一个pattern.
每个分支加上他们的后继命令称作一个子句.
每个子句必须以";;"结尾.
每个case语句以esac语句结束.
在这个例子中,我们使用disktest.
sh脚本的分支来发送一个更有选择性的警告信息:anny~/testdir>catdisktest.
sh#!
/bin/bash#Thisscriptdoesaverysimpletestforcheckingdiskspace.
space=`dfh|awk'{print$5}'|grep%|grepvUse|sortn|tail1|cutd"%"f1`case$spacein[16]*)Message="Allisquiet.
";;[78]*)Message="Startthinkingaboutcleaningoutsomestuff.
There'sapartitionthatis$space%full.
";;9[18])Message="Betterhurrywiththatnewdisk.
.
.
Onepartitionis$space%full.
";;99)Message="I'mdrowninghere!
There'sapartitionat$space%!
";;*)Message="Iseemtoberunningwithannonexitentamountofdiskspace.
.
.
";;esacecho$Message|mails"diskreport`date`"annyanny~/testdir>Youhavenewmail.
anny~/testdir>tail16/var/spool/mail/annyFromanny@octarineTueJan1422:10:472003ReturnPath:Received:fromoctarine(localhost[127.
0.
0.
1])byoctarine(8.
12.
5/8.
12.
5)withESMTPidh0ELAlBG020414for;Tue,14Jan200322:10:47+0100Received:(fromanny@localhost)byoctarine(8.
12.
5/8.
12.
5/Submit)idh0ELAltn020413foranny;Tue,14Jan200322:10:47+0100Date:Tue,14Jan200322:10:47+0100From:AnnyMessageId:To:anny@octarineBash新手指南68/91Subject:diskreportTueJan1422:10:47CET2003Startthinkingaboutcleaningoutsomestuff.
There'sapartitionthatis87%full.
anny~/testdir>当然你可以打开你的邮件程序来检查结果;这只是为了证明脚本发送一个正式的邮件.

更多使用case语句的例子可以在你系统的初始脚本目录找到.
初始化脚本使用start和stop分支来启动和停止系统进程.
可以在下一节找到一个更具理论性的例子.
7.
4.
总结总结总结总结本章我们学习了怎么在脚本中建立条件来根据命令的成功与否以执行不同的动作.

动作可以使用if语句来决定.
允许你进行算术和字符串比较和退出代码的测试,脚本所需的输入和文件.

一个简单的if/then/fi测试通常先于shell脚本中的命令为了防止产生输出,因此脚本可以容易的在后台或者通过cron运行.
更多复杂的条件定义通常放置在case语句.
在测试条件成功时,脚本可以使用exit0状态来明确地通知父进程.
在失败的时候,任何数字都可能返回.
根据返回的代码,父进程可以采取适当的动作.
7.
5.
练习练习练习练习第八章第八章第八章第八章编写交互脚本编写交互脚本编写交互脚本编写交互脚本本章我们将讨论怎么通过脚本来和合用户交流打印用户友好的消息和解释捕捉用户的输入提示用户输入使用文件描述符来读取和写入到多个文件8.
1.
显示用户消息显示用户消息显示用户消息显示用户消息8.
1.
1.
交互与否交互与否交互与否交互与否Bash新手指南69/91一些脚本根本不需要来自用户的交互信息.
非交互脚本的优势包括:脚本每次都以可以预测的行为运行.
脚本可以在后台运行.
然而许多脚本,需要来自用户的输入,或者在运行的时候给用户输出信息.
交互脚本的优势在于:可以建立更加灵活的脚本.
用户可自定义脚本使得其产生不同的行为.
脚本可以在运行过程中报告状态.
当编写交互脚本的时候,不要省略注释.
打印适当的信息的脚本能变的更加友好且更加容易调试.
一个脚本可能做一件完美的工作,但是如果脚本不通知用户正在进行的工作,你将会得到许多来自用户的帮助请求.
所以请把告诉用户等待计算完成的输出的提示信息包含进脚本.
如果可能的话,尝试提醒下用户需要等待多长的时间.
如果再执行某个特定任务的时候等待通常要持续很长时间,你可能会考虑把一些关于脚本输出进度的指示一起集成到脚本当中去.

当提示用户进行输入的时候,同样对输入数据的类型最好给出更多的相关信息.
同样在检查参数的时候也采取同样的使用方法信息.
Bash有echo和printf命令提供注释给用户,尽管你现在应该已经熟悉了echo的使用方法,但是我们在以下还是会讨论更多的例子.
8.
1.
2.
使用内建使用内建使用内建使用内建echo命令命令命令命令内建命令echo输出他的参数,以空格来分隔,以换行符来结束.
返回值总为0.
echo使用的一些选项:-e:转义反斜杠字符.
-n:禁止换行.
作为添加注释的一个例子,我们将把7.
2.
1.
2的feed.
sh和penguin.
sh改的好一点.
michel~/test>catpenguin.
sh#!
/bin/bash#ThisscriptletsyoupresentdifferentmenustoTux.
Hewillonlybehappy#whengivenafish.
Tomakeitmorefun,weaddedacouplemoreanimals.
if["$menu"=="fish"];thenif["$animal"=="penguin"];thenechoe"Hmmmmmmfish.
.
.
Tuxhappy!
\n"elif["$animal"=="dolphin"];thenechoe"\a\a\aPweetpeettreetppeterdepweet!
\a\a\a\n"elseechoe"*prrrrrrrt*\n"Bash新手指南70/91fielseif["$animal"=="penguin"];thenechoe"Tuxdon'tlikethat.
Tuxwantsfish!
\n"exit1elif["$animal"=="dolphin"];thenechoe"\a\a\a\a\a\aPweepwishpeeterdepweet!
\a\a\a"exit2elseechoe"Willyoureadthissign!
Don'tfeedthe"$animal"s!
\n"exit3fifimichel~/test>catfeed.
sh#!
/bin/bash#Thisscriptactsupontheexitstatusgivenbypenguin.
shif2"];thenechoe"Usageofthefeedscript:\t$0foodonmenuanimalname\n"exit1elseexportmenu="$1"exportanimal="$2"echoe"Feeding$menuto$animal.
.
.
\n"feed="/nethome/anny/testdir/penguin.
sh"$feed$menu$animalresult="$"echoe"Donefeeding.
\n"case"$result"in1)echoe"Guard:\"You'dbettergive'mafish,lesstheygetviolent.
.
.
\"\n";;2)echoe"Guard:\"Nowondertheyfleeourplanet.
.
.
\"\n";;3)echoe"Guard:\"BuythefoodthattheZooprovidesattheentry,you***\"\n"echoe"Guard:\"Youwanttopoisonthem,doyou\"\n";;*)echoe"Guard:\"Don'tforgettheguide!
\"\n";;esacfiecho"Leaving.
.
.
"Bash新手指南71/91echoe"\a\a\aThanksforvisitingtheZoo,hopetoseeyouagainsoon!
\n"michel~/test>feed.
shapplecamelFeedingappletocamel.
.
.
Willyoureadthissign!
Don'tfeedthecamels!
Donefeeding.
Guard:"BuythefoodthattheZooprovidesattheentry,you***"Guard:"Youwanttopoisonthem,doyou"Leaving.
.
.
ThanksforvisitingtheZoo,hopetoseeyouagainsoon!
michel~/test>feed.
shappleUsageofthefeedscript:.
/feed.
shfoodonmenuanimalname更多关于转义字符可以参考3.
3.
2.
节.
下表给出echo命令能识别的顺序总揽:表8-1.
echo命令使用的转义序列序列意义\a闹铃\b退格\c强制换行\e退出\f清除屏幕\n新行\rCarriagereturn.
\t水平制表符\v垂直制表符\\反斜杠\ONNNTheeightbitcharacterwhosevalueistheoctalvalueNNN(zerotothreeoctaldigits).
\NNNTheeightbitcharacterwhosevalueistheoctalvalueNNN(onetothreeoctaldigits).
\xHHTheeightbitcharacterwhosevalueisthehexadecimalvalue(oneortwohexadecimaldigits).
要得到更多关于printf命令的信息以及允许你格式化输出的方法,请参阅BashInfo页面.
8.
2.
捕获用户输入捕获用户输入捕获用户输入捕获用户输入8.
2.
1.
使用内建使用内建使用内建使用内建read命令命令命令命令8.
2.
2.
提示用户输入提示用户输入提示用户输入提示用户输入以下的例子向你展示了使用提示来向用户解释应该输入什么.
Bash新手指南72/91michel~/test>catfriends.
sh#!
/bin/bash#Thisisaprogramthatkeepsyouraddressbookuptodate.
friends="/var/tmp/michel/friends"echo"Hello,"$USER".
ThisscriptwillregisteryouinMichel'sfriendsdatabase.
"echon"Enteryournameandpress[ENTER]:"readnameechon"Enteryourgenderandpress[ENTER]:"readn1genderechogrepi"$name""$friends"if[$==0];thenecho"Youarealreadyregistered,quitting.
"exit1elif["$gender"=="m"];thenecho"YouareaddedtoMichel'sfriendslist.
"exit1elseechon"Howoldareyou"readageif[$agelt25];thenechon"Whichcolourofhairdoyouhave"readcolourecho"$name$age$colour">>"$friends"echo"YouareaddedtoMichel'sfriendslist.
Thankyousomuch!
"elseecho"YouareaddedtoMichel'sfriendslist.
"exit1fifimichel~/test>cpfriends.
sh/var/tmp;cd/var/tmpmichel~/test>touchfriends;chmoda+wfriendsmichel~/test>friends.
shHello,michel.
ThisscriptwillregisteryouinMichel'sfriendsdatabase.
Enteryournameandpress[ENTER]:michelEnteryourgenderandpress[ENTER]:mYouareaddedtoMichel'sfriendslist.
michel~/test>catfriends注意这里没有省略输出.
这个脚本仅仅储存Michel感兴趣的信息,但是除非你已经在里面了,否则将一直提示你已经被加入了列表.
其他人现在可以执行这个脚本:[anny@octarinetmp]$friends.
shBash新手指南73/91Hello,anny.
ThisscriptwillregisteryouinMichel'sfriendsdatabase.
Enteryournameandpress[ENTER]:annyEnteryourgenderandpress[ENTER]:fHowoldareyou22WhichcolourofhairdoyouhaveblackYouareaddedtoMichel'sfriendslist.
一会之后,friends列表开始开上去像这样:tille24blackanny22blackkatya22blondemaria21blackoutputomitted当然,这个情况并不是理想的,因为每个人都能编辑(但不是删除)Michel的文件.
你可以再这个脚本文件里使用特别的存取模式来解决问题,再Linux手册的介绍中见SUID和SGID.
8.
2.
3.
重定向和文件描述符重定向和文件描述符重定向和文件描述符重定向和文件描述符8.
2.
3.
1.
概要就像你知道的在shell的基本用法中,一个命令的输入和输出可以在执行完毕前被重定向,使用一个特殊的符号-重定向操作符-由shell来解释.
重定向夜可以用来为当前shell执行环境打开和关闭文件.
重定向也可以出现在一个脚本中,所以它可以从一个文件收到输入,比如,或者发送输出到一个文件.
然后,用户可以回顾这个输出文件,或者可以被另外一个脚本当作输入.

文件输入输出由追踪为一个给定的进程所有打开文件的整数句柄来完成.

这些数字值就是文件描述符.
最为人们所知的文件米描述符是stdin,stdout和stderr,文件描述符的数字分别是0,1和2.
这些数字和各自的设备是保留的.
Bash可以也可以把网络主机的TCP或者UDP端口也认为是一个文件描述符.
下面的输出展示怎么保留文件描述符指向真实的设备:michel~>lsl/dev/std*lrwxrwxrwx1rootroot17Oct207:46/dev/stderr>.
.
/proc/self/fd/2lrwxrwxrwx1rootroot17Oct207:46/dev/stdin>.
.
/proc/self/fd/0lrwxrwxrwx1rootroot17Oct207:46/dev/stdout>.
.
/proc/self/fd/1michel~>lsl/proc/self/fd/[02]lrwx1michelmichel64Jan2312:11/proc/self/fd/0>/dev/pts/6lrwx1michelmichel64Jan2312:11/proc/self/fd/1>/dev/pts/6lrwx1michelmichel64Jan2312:11/proc/self/fd/2>/dev/pts/6你可能想检查infoMAKEDRV和infoproc来得到更多关于/proc子目录和你的系统为每个运行的进程操纵文件描述符的方法的信息.
Bash新手指南74/91当你以命令行来运行一个脚本的时候,没有什么太多的改变,因为子shell进程会使用和父进程相同的文件描述符.
当没有这个的父进程存在的话,比如你使用cron来运行一个脚本,标准的文件描述符是管道或者其他(临时)文件,除非使用一些形式重定向.
在下面的例子中证明,展示了从例子脚本at的输出.
michel~>dateFriJan2411:05:50CET2003michel~>at1107warning:commandswillbeexecutedusing(inorder)a)$SHELLb)loginshellc)/bin/shat>lsl/proc/self/fd/>/var/tmp/fdtest.
atat>job10at2003012411:07michel~>cat/var/tmp/fdtest.
attotal0lrx1michelmichel64Jan2411:070>/var/spool/at/!
0000c010959eb(deleted)lwx1michelmichel64Jan2411:071>/var/tmp/fdtest.
atlwx1michelmichel64Jan2411:072>/var/spool/at/spool/a0000c010959eblrx1michelmichel64Jan2411:073>/proc/21949/fd还有一个使用cron的michel~>crontabl#DONOTEDITTHISFILEeditthemasterandreinstall.
#(/tmp/crontab.
21968installedonFriJan2411:30:412003)#(Cronversion$Id:chap8.
xml,v1.
82005/09/0512:39:22tilleExp$)3211***lsl/proc/self/fd/>/var/tmp/fdtest.
cronmichel~>cat/var/tmp/fdtest.
crontotal0lrx1michelmichel64Jan2411:320>pipe:[124440]lwx1michelmichel64Jan2411:321>/var/tmp/fdtest.
cronlwx1michelmichel64Jan2411:322>pipe:[124441]lrx1michelmichel64Jan2411:323>/proc/21974/fd8.
2.
3.
2.
错误重定向从先前的例子中,很清楚你可以为一个脚本提供输入和输出文件(更多参阅8.
2.
4.
),但是一些忘记错误重定向的企图-一些之后可以仰赖的输出.
同时,如果你幸运的话,错误会mai给你,可能的错误原因会被被揭示出来.
但是不幸的话,错误会导致你的脚本失败而且也不会被捕捉或者发送到任何地方,以至于你载调试的时候什么都做不了.
当重定向错误的时候,注意优先的顺序是有意义的.
比如,这个命令,发生在/var/spoollsl*2>/var/tmp/unaccessibleinspoolBash新手指南75/91将重定向ls命令的输出到文件/var/tmp/unaccessible-in-spool,这个命令lsl*>/var/tmp/spoollist2>&1将把标准输出和标准错误都重定向到文件spoollist,这个命令lsl*2>&1>/var/tmp/spoollist仅仅把标准输出定向到目标文件里,因为在标准输出重定向之前标准错误已经拷贝到标准输出.

为了方便,如果确定它们将不使用,错误常常重定向到/dev/null.
可以在你的系统的起始脚本里找到很多例子.
Bash允许你使用如下的结构来重定向标准输出和标准错误到名字是FILE扩展的结果的文件.
&>FILE等价于>FILE2>&1,在先前的一系列例子中使用.
也常和重定向组合输出到/dev/null,比如当你只是想执行一个命令,而不管产生什么输出或者错误.
8.
2.
4.
文件输入和输出文件输入和输出文件输入和输出文件输入和输出8.
2.
4.
1.
使用/dev/fd/dev/fd目录包含了名为0,1,2等的入口.
打开文件/dev/fd/N等价于复制文件描述符N.
如果你的系统提供/dev/stdin,/dev/stdout和/dev/stderr,你会看到它们分别等于/dev/fd/0,/dev/fd/1和/dev/fd/2.
/dev/fd的主要使用价值来自于shell.
这种机制允许程序以和其他路径名相同的方式使用路径名参数来操纵标准输入和标准输出.
如果/dev/fd在系统中不存在,你将不得不找一个办法来迂回解决这个问题.
比如可以使用(-)来表明程序需要从管道读取就可以达到目的.
一个例子:michel~>filterbody.
txt.
gz|catheader.
txtfooter.
txtThistextisprintedatthebeginningofeachprintjobandthanksthesysadminforsettingusupsuchagreatprintinginfrastructure.
Texttobefiltered.
Thistextisprintedattheendofeachprintjob.
cat命令首先读取文件header.
txt,然后他的标准输入是filter命令的输出,以footer.
txt结尾.
折线作为命令行参数涉及标准输入或者标准输出是一种误解,尽管已经在许多程序中被这么认为.
当指定折线作为第一个参数的时候也可能产生问题,也许他会被解释成一个先前命令的选项.
使用/dev/fd来允许一致性和防止混淆.
michel~>filterbody.
txt|catheader.
txt/dev/fd/0footer.
txt|lp在这个清晰的例子中,所有的输出被附加管道通过lp送往默认的打印机.
8.
2.
4.
2.
读取和execBash新手指南76/918.
2.
4.
2.
1.
分配给文件以文件描述符另外一种着眼文件描述符的方法是把他们认为是分配给文件一个数值.
你可以使用文件描述符值,而不是使用文件名.
内建命令exec是用来给文件分配一个文件描述符.
使用execfdN>file分配文件描述符N给file进行输出,execfdNexec4>result.
txtmichel~>filterbody.
txt|catheader.
txt/dev/fd/0footer.
txt>&4michel~>catresult.
txtThistextisprintedatthebeginningofeachprintjobandthanksthesysadminforsettingusupsuchagreatprintinginfrastructure.
Texttobefiltered.
Thistextisprintedattheendofeachprintjob.
文件描述符5使用这个文件描述符可能导致问题,参见AdvancedBash-ScriptingGuide第16章.
强烈建议不要使用它.
8.
2.
4.
2.
2.
在脚本肿读取以下是一个例子向你展示怎么样在文件输入和命令行输入中进行转换:michel~/testdir>catsysnotes.
sh#!
/bin/bash#Thisscriptmakesanindexofimportantconfigfiles,putsthemtogetherin#abackupfileandallowsforaddingcommentforeachfile.
CONFIG=/var/tmp/sysconfig.
outrm"$CONFIG"2>/dev/nullecho"Outputwillbesavedin$CONFIG.
"exec7>"$CONFIG"echo$rootpasswd>>"$CONFIG"Bash新手指南77/91exec0>"$CONFIG"echo"Savinghostsinformation.
.
.
"#firstprepareahostsfilenotcontaininganycommentsTEMP="/var/tmp/hosts.
tmp"cat/etc/hosts|grepvTEMP"exec7>"$CONFIG"echo"$ip1$name1$alias1">>"$CONFIG"echo"$ip2$name2$alias2">>"$CONFIG"exec0>"$CONFIG"rm"$TEMP"michel~/testdir>sysnotes.
shOutputwillbesavedin/var/tmp/sysconfig.
out.
Savingrootaccountinfo.
.
.
Entercommentor[ENTER]fornocomment:hintforpassword:bluelagoonSavinghostsinformation.
.
.
Entercommentor[ENTER]fornocomment:incentralDNSmichel~/testdir>cat/var/tmp/sysconfig.
outYourrootaccountinfo:root:x:0:0:root:/root:/bin/bashhintforpassword:bluelagoonYourlocalhostconfiguration:127.
0.
0.
1localhost.
localdomainlocalhost192.
168.
42.
1tintagel.
kingarthur.
comtintagelincentralDNS8.
2.
4.
3.
关闭文件描述符既然子进程继承打开文件描述符,那么在不时用文件描述符的时候关闭它将是一个良好的习惯,使用以下语句完成:execfdcatlistdirs.
sh#!
/bin/bash#Thisscriptprintsstandardoutputunchanged,whilestandarderroris#redirectedforprocessingbyawk.
INPUTDIR="$1"exec6>&1ls"$INPUTDIR"/*2>&1>&66>&\#Closesfd6forawk,butnotforls.
|awk'BEGIN{FS=print"YOUHAVENOACCESSTO"$2}'6>&exec6>&8.
2.
4.
4.
here文档经常性的,你定额脚本可能调用其他程序或者脚本来请求输入.
here文档提供了一种通知shell从当前源读取输入直到找到仅仅包含搜索字符的行.
所有8.
3.
总结总结总结总结本章,我们学习了如何提供用户注释和怎样提示用户进行输入.
通常使用echo/read组合.
我们也讨论了文件如何使用文件描述符和重定向来进行输入输出,以及怎样组合起来从用户那里得到输入.
我们强调了向用户提供充足信息的重要性.
就像常常别人在使用你的脚本的时候,最好提供足够多的信息.
Here文档是一种shell结构允许为用户建立列表,保留选择.
这种结构也能够用来在后台执行其他的交互式任务,而不加干涉.
8.
4.
练习练习练习练习第九章第九章第九章第九章重复性任务重复性任务重复性任务重复性任务9.
1.
for循环循环循环循环9.
1.
1.
如何工作如何工作如何工作如何工作9.
1.
2.
例子例子例子例子9.
2.
while循环循环循环循环9.
2.
1.
Whatisit1089.
2.
2.
例子例子例子例子9.
3.
until循环循环循环循环Bash新手指南79/919.
3.
1.
Whatisit1119.
3.
2.
例子例子例子例子9.
4.
I/O重定向和循环重定向和循环重定向和循环重定向和循环9.
4.
1.
输入重定向输入重定向输入重定向输入重定向9.
4.
2.
输出重定向输出重定向输出重定向输出重定向9.
5.
Break和和和和continue9.
5.
1.
内建内建内建内建break9.
5.
2.
内建内建内建内建continue9.
5.
3.
例子例子例子例子9.
6.
Makingmenuswiththeselectbuiltin.
1159.
6.
1.
概要概要概要概要.
1159.
6.
2.
子菜单子菜单子菜单子菜单9.
7.
内建内建内建内建shift9.
7.
1.
Whatdoesitdo1179.
7.
2.
例子例子例子例子9.
8.
总结总结总结总结9.
9.
练习练习练习练习第十章第十章第十章第十章深入变量深入变量深入变量深入变量10.
1.
变量变量变量变量种类种类种类种类10.
1.
1.
概要概要概要概要assignmentofvalues.
.
.
.
.
.
.
.
12010.
1.
2.
使用内建使用内建使用内建使用内建declare10.
1.
3.
常量常量常量常量10.
2.
数组数组数组数组变量变量变量变量.
122Bash新手指南80/9110.
2.
1.
创建数组创建数组创建数组创建数组10.
2.
2.
Dereferencingthe变量变量变量变量inanarray.
12210.
2.
3.
删除删除删除删除数组数组数组数组变量变量变量变量10.
2.
4.
数组数组数组数组例子例子例子例子10.
3.
Operationson变量变量变量变量10.
3.
1.
Arithmeticon变量变量变量变量.
12610.
3.
2.
变量的长度变量的长度变量的长度变量的长度10.
3.
3.
变量变量变量变量的转变的转变的转变的转变10.
4.
总结总结总结总结10.
5.
练习练习练习练习第十一章第十一章第十一章第十一章函数函数函数函数本章,我们将讨论什么是函数从命令行建立并显示函数脚本中的函数向函数传递参数使用函数的时机11.
1.
介绍介绍介绍介绍11.
1.
1.
什么是函数什么是函数什么是函数什么是函数shell函数是一种为后续操作组织命令的方法,使用单个名字来命名这些命令组或者过程.

在shell或者是脚本当中,这个过程的名字必须是唯一的.
所有用来组织函数的命令就像普通命令一样执行.
当以一个简单的命令来调用函数的时候,和该函数相关的命令就被执行.
函数在必须声明,然后在shell里执行:没有新的进程会被创建来打断这个命令.
11.
1.
2.
函数语法函数语法函数语法函数语法函数使用以下2种形式.
Bash新手指南81/91functionFUNCTION{COMMANDS;}或者FUNCTION(){COMMANDS;}两者都定义了一个shell函数FUNCTION.
内建的function命令是可选的;然而,如果不使用,必须在函数名后加上小括号.
通常的错误.
.
.
.
.
函数体必须以分号或者新行结尾11.
1.
3.
函数中参数的位置函数中参数的位置函数中参数的位置函数中参数的位置函数就像是迷你脚本:他们可以接受参数,他们可以使用只有在函数中有效的变量(使用本地内建shell)并且他们可以向调用者返回参数.
一个函数也有解释位置参数的机制,然而传递给函数的参数和传递给命令或者脚本的参数是不一样的.
当函数开始执行,在执行期间函数的参数变成位置参数.
扩展为位置参数的数量的特别符号#更新来反映这个变化.
位置参数0未改变.
Bash变量FUNCNAME在函数执行时被设置为函数的名字.
如果内建的return在函数中执行时,在调用完成后函数完成并且执行下一条命令.
当函数完成后,位置参数的值和特别参数#被重置到函数执行前的值.
如果一个数字参数被赋予return,那个状态就返回了.
一个简单的例子:[lydia@cointreau~/test]catshowparams.
sh#!
/bin/bashecho"Thisscriptdemonstratesfunctionarguments.
"echoecho"Positionalparameter1forthescriptis$1.
"echotest(){echo"Positionalparameter1inthefunctionis$1.
"RETURN_VALUE=$echo"Theexitcodeofthisfunctionis$RETURN_VALUE.
"}testother_param[lydia@cointreau~/test].
/showparams.
shparameter1Thisscriptdemonstratesfunctionarguments.
Bash新手指南82/91Positionalparameter1forthescriptisparameter1.
Positionalparameter1inthefunctionisother_param.
Theexitcodeofthisfunctionis0.
[lydia@cointreau~/test]注意函数的返回值或者退出代码通常储存在一个变量中,因此在以后也可以探测到.
你系统的初始脚本使用一种在条件测试中探测RETVAL值的技巧,像这样:if[$RETVAL-eq0];then或者像来自/etc/init.
d/amd的Bash优化特性使用的脚本例子:[$RETVAL=0]&&touch/var/lock/subsys/amd在&&后的命令只有在测试是真的时候才执行;这是一个简单的代替if/then/fi结构的方法.
函数的返回值通常被用作整个脚本的退出代码,你将会看到很多初始脚本用exit$RETVAL来结束.
11.
1.
4.
显示函数显示函数显示函数显示函数所有被当前shell所识别的函数可以用set不带选项地显示出来.
函数在他们被使用后保留,除非使用后进行unset.
which命令也可以显示函数:[lydia@cointreau~]whichzlesszlessisafunctionzless(){zcatPAGER"}[lydia@cointreau~]echo$PAGERless这是一种通常配置在用户shell资源配置文件里的函数.
函数比起别名和提供一个简单方便的方法来配合用户的环境更灵活.
以下是为了方便DOS用户:dir(){lsFcolor=autolFcolor=always"$@"|lessr}11.
2.
脚本中函数的例子脚本中函数的例子脚本中函数的例子脚本中函数的例子11.
2.
1.
循环利用循环利用循环利用循环利用Bash新手指南83/91在你的系统中有大量的脚本使用函数来以结构化的方法处理一系列命令.
在某些linux系统上,比如,你可以找到/etc/rc.
d/init.
d/functions定义文件,使用在所有的初始化脚本中.
使用这个方法通常秩序编写一次,常见的任务比如检查进程是否运行,开始或者停止一个守护进程等等.
如果某些任务还需要一次,代码就可以重新循环使用.
这些文件中的checkpid函数:#Checkif$pid(couldbeplural)arerunningcheckpid(){localiforiin$*;do[-d"/proc/$i"]&&return0donereturn1}这个函数在相同的脚本中在其他脚本的函数中被重用.
守护进程,多数使用在启动一个服务进程的起始脚本中.
11.
2.
2.
设置路径设置路径设置路径设置路径本节可能可以在你的/etc/profile文件中找到,pathmunge函数用来定义然后为root和其他用户设置路径:pathmunge(){if!
echo$PATH|/bin/egrepq"(^|:)$1(thenif["$2"="after"];thenPATH=$PATH:$1elsePATH=$1:$PATHfifi}#Pathmanipulationif[`idu`=0];thenpathmunge/sbinpathmunge/usr/sbinpathmunge/usr/local/sbinfipathmunge/usr/X11R6/binafterunsetpathmunge这个函数把第一个参数设置为路径名.
如果路径名不在当前路径中,就把它加入.
传给函数的第二个参数定义了路径是加入到当前PATH之前还是之后.
普通用户只把/usr/X11R6/bin加入到他们的路径中,当root得到了一些包含系统命令的额外目录.
使用完毕后,函数unset所以就不存在了.
Bash新手指南84/9111.
2.
3.
远程备份远程备份远程备份远程备份以下的例子是用来我用来备份我的文件的.
使用SSH密钥来启用远程连接.
其中定义了2个函数,buplinux和bupbash,每个都产生一个a.
tar文件,然后压缩送往远程服务器.
最后,本地拷贝被删除.
星期天,只有bupbash运行.
#/bin/bashLOGFILE="/nethome/tille/log/backupscript.
log"echo"Startingbackupsfor`date`">>"$LOGFILE"buplinux(){DIR="/nethome/tille/xml/db/linuxbasics/"TAR="Linux.
tar"BZIP="$TAR.
bz2"SERVER="rincewind"RDIR="/var/www/intra/tille/html/training/"cd"$DIR"tarcf"$TAR"src/*.
xmlsrc/images/*.
pngsrc/images/*.
epsecho"Compressing$TAR.
LOGFILE"bzip2"$TAR"echo".
.
.
done.
">>"$LOGFILE"echo"Copyingto$SERVER.
LOGFILE"scp"$BZIP""$SERVER:$RDIR">/dev/null2>&1echo".
.
.
done.
">>"$LOGFILE"echoe"DonebackingupLinuxcourse:\nSourcefiles,PNGandEPSimages.
\nRubbishremoved.
">>"$rm"$BZIP"}bupbash(){DIR="/nethome/tille/xml/db/"TAR="Bash.
tar"BZIP="$TAR.
bz2"FILES="bashprogramming/"SERVER="rincewind"RDIR="/var/www/intra/tille/html/training/"cd"$DIR"tarcf"$TAR""$FILES"echo"Compressing$TAR.
LOGFILE"bzip2"$TAR"echo".
.
.
done.
">>"$LOGFILE"echo"Copyingto$SERVER.
LOGFILE"scp"$BZIP""$SERVER:$RDIR">/dev/null2>&1Bash新手指南85/91echo".
.
.
done.
">>"$LOGFILE"echoe"DonebackingupBashcourse:\n$FILES\nRubbishremoved.
">>"$LOGFILE"rm"$BZIP"}DAY=`date+%w`if["$DAY"lt"2"];thenecho"Itis`date+%A`,onlybackingupBashcourse.
">>"$LOGFILE"bupbashelsebuplinuxbupbashfiechoe"Remotebackup`date`SUCCESS\nLOGFILE"这个脚本从cron运行,意味着没有用户交互,所以我们对scp的标准错误进行重定向到/dev/null.
所有的分开的步骤可以组合到下列的命令可能引起争论tarcdir_to_backup/|bzip2|sshserver"cat>backup.
tar.
bz2"然而,如果你对可能恢复脚本错误的中间的结果感兴趣,这不是你想要的.

CloudCone,美国洛杉矶独立服务器特价优惠,美国洛杉矶MC机房,100Mbps带宽不限流量,可选G口,E3-1270 v2处理器32G内存1Gbps带宽,69美元/月

今天CloudCone发布了最新的消息,推送了几款特价独立服务器/杜甫产品,美国洛杉矶MC机房,分配100Mbps带宽不限流量,可以选择G口限制流量计划方案,存储分配的比较大,选择HDD硬盘的话2TB起,MC机房到大陆地区线路还不错,有需要美国特价独立服务器的朋友可以关注一下。CloudCone怎么样?CloudCone服务器好不好?CloudCone值不值得购买?CloudCone是一家成立于2...

爱用云互联租用服务器租美国、日本、美国、日本、购买2天内不满意可以退换,IP可免费更换!

爱用云互联怎么样?爱用云是一家成立于2018年的老牌商家旗下的服务器销售品牌,是正规持证IDC/ISP/IRCS商家,主要销售国内、中国香港、国外服务器产品,线路有腾讯云国外线路、自营香港CN2线路等,都是中国大陆直连线路,非常适合免备案建站业务需求和各种负载较高的项目,同时国内服务器也有多个BGP以及高防节点。专注为个人开发者用户,中小型,大型企业用户提供一站式核心网络云端服务部署,促使用户云端...

LOCVPS:美国XEN架构VPS七折,全场八折,日本/新加坡XEN架构月付29.6元起

LOCVPS发来了针对XEN架构VPS的促销方案,其中美国洛杉矶机房7折,其余日本/新加坡/中国香港等机房全部8折,优惠后日本/新加坡机房XEN VPS月付仅29.6元起。这是成立较久的一家国人VPS服务商,目前提供美国洛杉矶(MC/C3)、和中国香港(邦联、沙田电信、大埔)、日本(东京、大阪)、新加坡、德国和荷兰等机房VPS主机,基于XEN或者KVM虚拟架构,均选择国内访问线路不错的机房,适合建...

rsync为你推荐
域名注册注册域名需要什么吗?me域名注册请问 .me 域名在哪里注册或查看,至少万网查不到虚拟主机申请域名申请以及虚拟主机国外网站空间怎么查看一个网站的空间是在国内还是在国外啊?网站空间免备案哪里能找到免费、免备案的空间?云南虚拟主机云南服务器托管云南虚拟主机云南虚拟主机,公司网站用本地客户,云南数据港怎么样?淘宝虚拟主机淘宝买虚拟主机空间好吗?新加坡虚拟主机新加坡虚拟主机无法访问,Godaddy回邮件说是域名的问题?www二级域名www是二级域名,w也是二级域名 权重一样高吗?
php网站空间 拜登买域名批特朗普 金万维动态域名 2019年感恩节 warez 日本软银 t楼 香港服务器99idc 免费主机 海外服务器 线路工具 阿里云代金券 网通代理服务器 免费ftp站点 有益网络 监控服务器 net空间 云服务器比较 德讯 万网空间 更多