admin 管理员组文章数量: 1184232
2024年3月13日发(作者:weblogic12c创建域)
《LINUX与UNIX SHELL编程指南》
读书笔记
二次发布版
张启峰
Email: zqf620@
一些废话
这是笔者第一本发到网络上的 Linux 读书笔记,利用今年十一长假,重
新编辑排版了一下,再次发到网上,姑且称为“二次发布版”吧!
关于《LINUX与UNIX SHELL编程指南》这本书,我看的是
的电子版,在很多网站都可以下载到。虽然看电子书很累人,但我还是建议不
想掏钱买书的朋友看看(有钱也不一定买的到,反正我逛书店时就没有看到过
有卖这本书的),它不愧为一本经典的讲解shell编程的书。
当初,写这本笔记时,花了很大的力气。参考了不少资料,在我认为书中
某些讲的不详细的地方,在笔记中也记述的很详细。读者可以发现,这本笔记
并不是简单的摘抄。
当然,记笔记的过程也是对我的一个提高,比如,awk和脚本编程中可以
遇到的getopts,这两个东东我一直就没搞清楚,记笔记的过程中我就把它们
搞清白了(我个人认为关键是要静下心来学)。希望这本笔记能对读者您有所
帮助!
在笔记中给出了很多举例,这些例子都在 Red Hat Linux 9 和 Red Flag
Advanced Server 4.1 中测试通过,大多数例子还给出了注释(使用C风格的
双斜线”//”注释符号)。
好了,不再废话了。最后,给您推荐两本书,都是美国佬写的。一本是机
械工业出版社出版的O'Reilly的《学习Bash(第二版)》,一本是人民邮电出
版社出版的Sams的《精通Shell编程(第二版)》。
张启峰(zqf620@)
2005年10月4日
《LINUX与UNIX SHELL编程指南》读书笔记 第 1 页,共 58 页
第1章 文件安全与权限
1. 一个文件一经创建,就具有三种基本访问方式:
1) 读(r): 可以显示该文件的内容。
2) 写(w): 可以编辑或删除它。
3) 执行(x): 如果该文件是一个shell脚本或程序的话。
2. 按照所针对的用户,文件的权限可分为三类:
1) 文件属主: 创建该文件的用户。
2) 同组用户: 拥有该文件的用户组中的任何用户。
3) 其他用户: 即不属于拥有该文件的用户组的某一用户。
-l (列出目录内容)命令的输出的分析
drwxr-xr-x 2 root root 4096 Oct 14 20:18 bin
1) 第1个部分第1个字符: 表示文件的类型,详细说明见下。
2) 第1个部分第2-10个字符: 分为3组(triplet),分别表示文件的属主、组用户和其它用户的权限。
3) 第2个部分: 表示该文件的硬链接的数目。
4) 第3个部分: 表示文件的属主。
5) 第4个部分: 文件的属主(root)所在的缺省组(也是root组)。
6) 第5个部分: 表示文件的长度(以字节byte为单位)。
7) 第6-7个部分: Oct 14 20:18 表示文件的更新时间。
8) 第8个部分: 该文件的文件名。
4.文件的类型
1) d : 目录文件,目录也是一种文件 (directory)
2) l : 符号链接(指向另一个文件) (link)
3) b : 块设备文件 (block device)
4) c : 字符设备文件 (charactor device)
5) p : 命名管道文件 (named piple)
6) s : 套接字文件 (socket)
7) - : 普通文件,或者更准确地说,不属于以上几种类型的文件
5.文件的权限位
1) 一个文件的权限位由9个字符组成,分成3个triplet,分别表示文件属主(owner)、文件属主所属缺省组的
用户(group)、系统中其他用户(other)所拥有的权限。
《LINUX与UNIX SHELL编程指南》读书笔记 第 2 页,共 58 页
eg: rw- 表示可读写,不可执行
r-- 表示可读,不可写、执行
3) 在文件权限位的owner triplet第3个位置的字符如果设置为"s",称为SUID。当某用户执行该文件时,系统
用文件owner的uid替代实际执行该文件的用户的uid,文件会认为是owner在执行它。
4) 在文件权限位的group triplet第3个位置的字符如果设置为"s",称为SGID。当某用户执行该文件时,系统
用文件组拥有者的gid替代实际执行该文件的用户的gid。当在某个目录文件上设置SGID时候,则在该目录
下的所有文件和子目录都会继承使用该目录的GID来代替实际执行者的GID。
5) 文件设置了SUID或SGID,一般来说文件的owner或group应该有执行(x)权限。如果没有x权限,设置
SUID或SGID是没有意义的,triplet上第3个字符就会是"S"(大写)而不是"s"(小写)。eg: rwSr-Sr--
6) 给可执行文件设置SUID/SGID可能带来安全风险,许多系统因而忽略SUID/SGID权限设置
7) 在某些目录(如/tmp)的other triplet的第3个字符设置为"t"。一般来说,在目录的other triplet上设置w和x
权限,则任何用户都可以在该目录下执行、删除文件,而设置"t"的作用就是保证非目录的owner用户不能删
除目录下的文件。
6.使用chmod命令改变权限位
1) 符号模式Usage: chmod [who]
① who: 可以是 u g o a,表示给文件的owner、group、other和all用户设置权限。省略时默认为a。
② operator: 可以是+ - =,分别表示增加、取消、指定权限
③ perm: 可以是 r w x s(suid和guid) t(粘性位) l(给文件加锁,使其他用户无法访问)
④ 举例: chmod u+xw o-w myfile
2) 绝对模式Usage: chmod mode file_name
① mode: 4位8进制数,每一位分别用于SUID和SGID、属主权限、组权限、其他用户权限。当用户给出的
mod值小于4位时,系统会在数字前面加0补齐。
② 权限r w x 分别用数字4 2 1 表示, suid guid用4 2表示,各个triplet的数字相加可得mod值。
eg: rwxr-xr-- 为754,rwsr-xr-x 为4755, rwsr-sr-x 为6755 -rwxrwSr-- 为2764
7.目录文件的权限(r w x)的含义
1) r: 可以列出该目录中的内容。
2) w: 可以在目录中创建、修改文件。目录的w位不设置,即使拥有目录中某文件的w权限也不能写该文件。
3) x: 可以搜索和访问该目录。x位不设置,不能访问目录下的任何文件,即使拥有文件的权限。
和chgrp 修改文件的拥有权
1) chown Usage: chown [选项] [owner][.group] file_name
// 给myfile的owner增加x w权限,去除other用户的w权限
《LINUX与UNIX SHELL编程指南》读书笔记 第 3 页,共 58 页
② chmod的常用选项: -R 对指定目录所有文件和子目录递归式地进行同样的操作
-h 如果file_name是符号链接,则只对符号链接本身进行操作
③ owner 和 .group 表示文件拥有者名和文件所属组名,可以使用uid/gid表示。两者不能同时省略
④ 举例: chown /etc/httpd // 将目录/etc/httpd的属主修改为http,组修改为http
2) chgrp Usage: chgrp [选项] group file_name
① chgrp命令只能用来修改文件的所属组。chgrp和chown用法类似,选项也一样。
② 举例: chown http /etc/httpd // 将目录/etc/httpd的所属组修改为http
3) 查询用户信息和用户所属组信息
id [user_name] 或 groups [user_name]
确定系统创建文件时的缺省权限位。
1) Usage: umask [umask_mod]
2) umask_mod的计算方法: umask_mod=777-文件缺省权限值。
3) 系统不允许你在创建一个文件时就赋予它执行权限,即umask_mod为002时,创建文件的缺省权限值为
665,创建目录的缺省权限值为775。
9.符号链接
1) Usage: ln -s source_path target_path
2) 存在2种类型的链接: 硬链接和软链接。软链接又称位符号链接,符号链接实际上是指向一个文件的指针,
符号链接和Windows OS的快捷方式有点类似。
3) 不管是否在同一个文件系统中,都可以创建链接。在创建链接的时候,不要忘记在原有目录设置执行权限。
链接一旦创建,链接目录将具有权限777(rwxrwxrwx),但是实际的原有文件的权限并未改变。
4) 举例: ln -s /var/tmp /home/zqf/tmp // 在zqf主目录创建一个名为tmp,指向/var/tmp的符号链接
第2章 使用find和xargs
1.有时可能需要在系统中查找具有某一特征的文件(如文件权限、文件属主、文件长度、文件类型等)。find是
一个非常有效的工具,它可以递归式遍历当前目录甚至于整个文件系统(本地和网络文件系统)来查找某些文件
或目录,只要你具有相应的文件或目录的权限。
命令的使用
1) Usage : find [path_name ...] [expression]
《LINUX与UNIX SHELL编程指南》读书笔记 第 4 页,共 58 页
3) expression : 用于指定搜索的方式、条件和要执行的操作等。如果expression省略,则默认使用 -print 作为
expression。expression可由4类项目组成:
① OPTION(选项) : 用于指定find命令的搜索方式,一般把OPTION放在expression的开头。
② TEST(测试) : 用于指定find命令的检索条件,只有符号条件的文件才会被指定的ACTION处理。
③ ACTION(操作) : 用于指定对find的搜索结果执行的操作。省略ACTION时预设为 -print。
④ OPERATOR(运算) : 对TEST或ACTION进行与、或、非 等运算。
4) find在执行时,一般会将第1个"-"字符之后的命令行参数都看作expression,把之前的参数都看作为要搜
索的路径。
3.常用的OPTION项目
0) OPTION项目可以省略,find默认从指定路径目录开始递归地向下层子目录搜索。
1) -depth : 在查找文件时,首先查找当前目录中的文件,然后再在其子目录中查找。
2) -maxdepth level : 进入指定的目录下层目录搜索时,最深不超过level(一个非负整数)层。
eg: find . -maxdepth 0 -name "1" // 只在当前目录而不向下层子目录搜索名为"1"的文件或目录
3) -follow : 如果find命令遇到符号链接文件,就跟踪至链接所指向的文件。
4) -mount : 不搜索其它文件系统上的目录(不跨越文件系统mount点)。
5) -daystart : 从当日起始时开始而不是从24小时之前开始计算时间(如-amin, -atime, -cmin, -ctime, -mmin 和 -
mtime )。
6) -noleaf : 不为"目录中子目录数量比硬链接数少2"这种假设做优化。这个选项在搜索那些不遵循UNIX文件
系统链接约定的文件系统(比如CD-ROM,MS-DOS文件系统或AFS卷的加载点)时使用。在普通的UNIX文件
系统中,每个目录至少有两个硬链接: 它的名字和它的'.'条目。另外,它的每个子目录(假如有的话)还会各有一个
'..'链接到它。在find检索一个目录时,发现子目录数比它的链接数少二时,它就知道目录中的其他条目并非目
录(而是目录树中的叶(`leaf')节点)。除非需要检索的是这个叶节点,否则没必要去处理它。这样可以带来很大
的搜索搜索速度的提升。
4.常用的TEST项目
0) 在TEST项目的一些选项中有时会使用数字,数字N(非负整数)可以以3种形式给出:
+N 表示比N大, -N 表示比N小, N 表示正好是N
1) -name PATTERN : 查找文件名符合模式PATTERN(一般要加双引号)的文件,也可直接使用文件名。
eg: find . -name "[a-z][a-z][0-9][0-9].txt" -print // 此命令可以返回名为的文件
2) -empty : 查找空白文件,它可以是一般文件或目录。
3) -lname PATTERN: 只查找符合PATTERN的符号链接文件。
4) -iname 和 -ilname : 分别与 -name 和 -lname 类似,只是不区分大小写。
《LINUX与UNIX SHELL编程指南》读书笔记 第 5 页,共 58 页
6) -type C : 查找某一类型的文件。C可以是b c d p l s f (块设备 字符设备 目录 命名管道 符号链接 socket 正
规文件)。
eg: find ~ -type l // 此命令返回当前用户的主目录内所有的符号链接文件的文件名
7) -size N[bckw] :查找使用N个单位空间的文件,可以使用b(块,512字节) c(字节) k(KB) w(2字节)为单位,
不带单位时预设为b。
eg: find ~ -size +100k -size -1024k // 此命令返回文件尺寸大于100k小于1M的文件的文件名
8) -fstype FSTYPE : 查找位于某一类型文件系统中的文件,如vfat ext3 nfs等
9) -user USERNAME : 查找文件属主为USERNAME的文件。
-uid UID : 查找文件属主的uid为UID的文件。
10) -group GROUPNAME : 查找文件所属组为GROUPNAME的文件。
-gid GID : 查找文件所属组的gid为GID的文件。
11) -nouser : 查找无有效属主的文件,即该文件的属主在/etc/passwd中不存在。
-nogroup : 查找无有效所属组的文件,即该文件所属的组在/etc/groups中不存在。
12) -perm MODE : 查找文件的权限设置等于MODE的文件。MODE前可加"+"或"-",表示权限设置比MODE
宽松)或更严格。
13) -anewer FILENAME : 查找其存取(access)时间比文件FILENAME的修改时间更接近现在的文件。
-cnewer FILENAME : 查找其状态改变(change)时间比文件FILENAME的修改时间更接近现在的文件。
-newer FILENAME : 查找其内容修改(modify)时间比文件FILENAME的修改时间更接近现在的文件。
-amin N : 查找在指定时间(N为分钟)被存取过的文件。
-cmin N : 查找在指定时间(N为分钟)更改过文件状态的文件。
-mmin N : 查找在指定时间(N为分钟)修改过数据内容的文件。
-atime N : 查找在指定时间(N为天)被存取过的文件。
-ctime N : 查找在指定时间(N为天)更改过文件状态的文件。
-mtime N : 查找在指定时间(N为天)修改过数据内容的文件。
注: 上面这些选项分别涉及到文件的3种时间: 文件存取时间(access)、文件状态改变时间(status change) 和
文件内容修改时间(modify),也就是在ls -l 命令输出中显示的时间。
5.常用ACTION
1) -print : 以完整文件路径名的形式将find的搜索结果显示到标准输出,以NEWLINE分隔各个文件名。
2) -ls : 以"ls -l"命令的格式将find的搜索结果显示到标准输出。
3) -exec CMD {} ; : 把find的搜索结果作为shell程序CMD的文件名参数,并执行CMD程序。
eg: find /logs -mtime +5 -exec rm -rf {} ; // 删除/logs目录中更改时间在5日以前的文件
4) -ok CMD {} ; : 同上,是一种更安全的模式,在执行每个命令前,会提示用户来确定是否执行。
《LINUX与UNIX SHELL编程指南》读书笔记 第 6 页,共 58 页
6.常用的OPERATOR
1) EXPR1 EXPR2 或 EXPR1 -a EXPR2 或 EXPR1 -and EXPR2 : 把2个EXPR相与。
eg: find ~zqf -size +10k -name "*.c" // 从zqf的主目录开始搜索大于10kB的C源程序文件
2) EXPRT1 -o EXPR2 或 EXPR1 -or EXPR2 : 把2个EXPR相或。
eg: find . -name "*.c" -or -name "*.cpp" // 从当前目录开始搜索C或C++源程序文件
3) ! EXPR 或 -not EXPR : 对EXPR取反。
eg: find ~zqf ! -user zqf // 查找zqf的主目录中属主不是zqf的文件或目录
4) ( EXPR ) : 当出现多个OPERATOR时,用来改变OPERATOR的运算顺序。
eg: find . ! ( -user zqf -name "*.awk" )
1) Usage: xargs CMD (从管道中获取CMD命令的参数)
2) xargs常常与find命令一起使用,用于取代find的-exec参数。有几个原因:
① find的-exec参数有很多局限。比如,递给exec的命令长度有限制,在某些系统上-exec参数只能调用很少
的shell命令等。
② 某些系统上-exec CMD选项会为find的搜索结果中的每一个文件名启动一个CMD进程,而不是把搜索结
果作为一个参数文件列表整个传给CMD程序,当搜索结构很多时,会严重影响系统性能。xargs CMD 把从管
道获取的参数作为一个参数列表一次传给CMD程序。
3) find和xargs联合使用举例: find . -perm -7 | xargs chmod o-w // 在当前目录下查找所有用户具
有读、写和执行权限的文件,并收回相应的写权限
第3章 后台执行命令
1) cron是系统主要的调度进程,可以在无需人工干预的情况下运行作业,与Windows的"计划任务"类似。
2) cron守护进程支持crontab和at,用户可以通过这2个程序来实现定时调度作业。
b命令允许用户提交、编辑或删除相应的作业。
1) 要想让cron来定时调度执行用户指定的程序,需要2个步骤:
① 按照crontab文件的格式创建用户的crontab文件。
② 使用crontab命令向cron提交用户的crontab文件。
2) 系统管理员可以通过设置/etc目录下的和文件来禁止或允许用户使用crontab。
3.创建用户的crontab文件:
1) crontab文件由若干条记录组成,一条记录对应一个要运行的命令。注释行要在行首加#。
《LINUX与UNIX SHELL编程指南》读书笔记 第 7 页,共 58 页
① 时间用数字表示,其中星期用0~6(0表示星期天),小时用1~23(0表示子夜)
② <>表示空格,作为域分隔符,每一条记录必须含有5个时间域,而且每个域之间要用空格分隔。
③ 在这些表示时间的域中,可以用横杠"-"来表示一个时间范围,可以使用逗号",",使用星号*来表示对某个表
示时间的域没有特别的限定。例如,你希望星期一至星期五运行某个作业,那么可以在星期域使用"1-5"来表
示。如果希望星期一和星期四运行某个作业,只需要使用"1,4"来表示。如果希望每天都运行某作业,应该在日
域填入"*"。
④举例: echo "10 1 * * 6,0 /bin/find ~zqf -name "core" -exec rm {} ;" >
// 上面的例子创建了一个用户crontab文件,表示每周六、周日的1:10运行一个find命令。
4.用户提交用户crontab文件:
1) Usage: crontab user_cronfile
2) 用户提交了crontab文件后,cron会把用户crontab文件中的内容添加到/var/spool/cron目录下一个与用户
名同名的文件中,用户第一次使用cron之前不存在/var/spool/cron目录下的同名文件。
3) 举例: crontab
// 用户zqf执行此命令后,cron将中的内容添加到文件/var/spool/cron/zqf中
4)crontab Usage: crontab [-u USERNAME] [-e -l -r]
① -u USERNAME : 编辑指定用户名的crontab文件。
② -e : 直接编辑crontab文件/var/spool/cron/
③ -l : 列出crontab文件/var/spool/cron/
④ -r : 删除/var/spool/cron/
允许用户向cron守护进程提交作业,使其在指定的稍后时间运行。
1) 一旦一个作业被提交,at命令将会保留所有当前的环境变量,包括路径,不象crontab只提供缺省的环境。
该作业的所有输出都将以电子邮件的形式发送给用户,除非你对其输出进行了重定向,绝大多数情况下是重定
向到某个文件中。
2) 和crontab一样,系统管理员可以通过/etc目录下的和文件来控制哪些用户可以使用at命
令。一般来说,对at命令的使用不如对crontab的使用限制那么严格。
3) 向at提交一个作业后,at将为该作业分配一个唯一的作业号,进入at的队列,作业运行后退出队列。
4) 提交给at的作业,只能在指定的时间运行一次,不能象crontab那样周期性运行。
5.向at提交作业
1) 命令行方式: 一般在提交shell脚本时,使用命令行方式。
① Usage: at -f SCRIPT_FILE [-m] TIME
② SCRIPT_FILE : 是脚本文件名,可以把要提交给at的作业写到脚本文件中,然后提交给at。
③ -m : 作业完成后给用户发邮件。
《LINUX与UNIX SHELL编程指南》读书笔记 第 8 页,共 58 页
2) 交互方式: 在交互方式下,要提交的作业直接从控制台输入。
① Usage: at [-m] TIME
② 在命令行下执行"at TIME"命令后,就进入at命令提示符( at> )状态,在at提示符状态下可以输入shell命
令,一行输入一条shell命令,可以输入多行,最后按"Ctrl+D"退出。
③ 举例: $ at 21:10
at> find / -name "passwd" -print
at>
: 作业被指定的时间,at的时间格式很灵活,时间粒度可以是时分、月日年。常见的格式有:
1) HH:MM : 这是最普遍的格式。比如21:30、9:15 等
2) am和pm : 比如10am、4pm、9:25pm等
3) MMDDYY和MM/DD/YY: 比如9:30pm 022005、11:50 02/20/2005等
4) tomorrow和today : 比如10pm today、21:30 tomorrow等
5) now +N uint : unit为时间单位,可以是minutes(min minute)、hours(hour) days(day)
比如 now+3min、now +2days、now +12hours等
6) +N unit : 比如9pm +2days、11:30 +4min等
的其它操作
1) 查看中已提交到at队列等待运行的作业: at -l 或 atq
2) 取消还未运行的作业: at -r job_number 或 atrm job_number
8.&命令 把作业放到后台执行
1) 当在前台运行某作业时,终端被该作业占据,用户不能使用终端;而把作业放在后台运行就不会占据终端。
2) 当在后台执行作业时,用户可以继续使用终端做其他事情。但是作业在后台运行一样会将结果输出到屏幕
上,干扰你的工作。如果放在后台运行的作业会产生大量的输出,最好使用下面的方法把它的输出重定向到某
个文件中。比如 command >out_file 2>&1 &
3) 适合后台运行的作业是那些非交互式的作业。需要用户交互的命令不要放在后台执行,否则系统就会始终等
待用户的输入。
9.向后台提交作业
1)Usage: CMD &
2)举例: find /etc -name "*.conf" -print > 2>&1 &
nohup命令可以在你退出帐户之后继续运行相应的后台进程
1) Usage: nohup CMD &
2) 如果使用nohup命令提交后台作业,那么在缺省情况下该作业的所有输出都被重定向到一个名为
的文件中,除非另外指定了输出文件。
《LINUX与UNIX SHELL编程指南》读书笔记 第 9 页,共 58 页
第4章 文件名置换
1.元字符 可在命令行上匹配文件名
1) 使用星号"*" : 可以匹配文件名中的任何字符串,包括空字符串。
eg: ls app* // 此命令可以列出文件app、appdva、appdva_SLA等
2) 使用问号"?" : 可以匹配文件名中的任何单个字符。
eg: ls conf.??.log // 此命令可以列出文件、等
3) 使用"[...]" : 可以匹配方括号[]中出现的任何单个字符。还可以使用"-"来连接两个字母或数字,以此来表示一
个范围。
eg: ls log.[0-5]* // 此命令可以列出文件log.0321、log.2987、log.5367等
4) 使用" [!...]" : 与"[...]"相反,匹配不属于方括号"[!...]"中出现字符的单字符。
eg: ls log.[!0-9] // 此命令可以列出文件等
第5章 shell输入与输出
将一行字符串显示到标准输出
0) echo命令的一些细节在System V、BSD和Linux这三种Like-UNIX系统上不同,这里以Linux系统为
主。
1) Usage: echo [-e] [-n] STRING
① STRING : STRING是要输出的字符串,其中可以包含shell变量名、转义符等,一般用双引号括起来。
② -e : Linux的echo缺省不解释STRING中的转移符,除非加上此选项。
③ -n : echo缺省在输出STRING后输出NEWLINE(换行),使用此选项echo将不输出NEWLINE。
2) echo支持的转移符:
NNN ASCII码为NNN(8进制)的字符,NNN如果不是一个合理的值,将直接按照字面打印
a 响铃
f 换页
t
从键盘或文件的某一行文本中读入信息,并将其赋给变量。
b
n
v
退格
换行
c
r
去除结尾NWELINE字符
回车
反斜线 水平制表符 垂直制表符
3) 举例: echo -e "User: $USERtUID: $UID" // 显示 User: zqf UID: 500
《LINUX与UNIX SHELL编程指南》读书笔记 第 10 页,共 58 页
2) 如果只指定了一个变量,read将会把输入行的所有内容赋给该变量,直至遇到第一个文件结束符或回车。
3) 如果指定了多个变量,read用空格(环境变量IFS)作为分隔符把输入行分成多个域,分别赋给各个变量。
4) 输入文本分隔出的域数量多于read给出的变量数,read将所有的超长部分赋予最后一个变量。
一个简单而通用的命令,可以用它来显示文件内容,创建文件,还可以用它来显示控制字符。
1) 显示文件内容: cat myfile | more // cat命令不会在文件分页符处停下,它会一下显示完整个文件
2) 创建文件: cat file1 file2 file3 > bigfile // 创建一个名为bigfile的文件,包含三个文件的内容
cat >myfile // 创建一个新文件,并向其中输入一些内容,输入完后按
3) 显示文件中控制字符: cat -v filename
4.管道 可以通过管道把一个命令的输出传递给另一个命令作为输入。管道用竖杠"|"表示。
1) Usage: command1 | command2
2) 举例: ls | grep "*.c" // 将ls命令的输出作为grep命令的输入,即在当前目录下搜索C源程序文件
3) sed、awk和grep等程序都很适合用管道,特别是在shell命令行下。
它把输出的一个副本输送到标准输出,另一个副本拷贝到相应的文件中
1)Usage: tee -a filename
① -a : 表示追加到文件末尾。
② tee命令应该和管道结合使用
2) 举例: who | tee // who命令的输出不仅会输出到标准输出,还会输入到文件
6.标准输入、输出和错误
1) 文件描述符: 文件描述符是从0开始的整数,指向与进程相关的特定数据流。当进程启动时,通常打开三个
文件描述符,分别对应三种标准的I/O: 标准输入(文件描述符0),标准输出(文件描述符1),标准错误(文件描
述符2)。
2) 标准输入(STDIN) : 它是命令的输入,缺省和终端的键盘关联。
3) 标准输出(STDOUT): 它是命令的输出,缺省和终端的屏幕关联。
4) 标准错误(STDERR): 它是命令的错误信息输出,缺省也和终端的屏幕关联。
5) 如果进程打开了额外的文件进行输入和输出,则其被设置为下一个可用的文件描述符,从3到9。
7.文件重定向
1) 在执行命令时,命令的标准输入、输出和错误是和文件描述符0、1、2关联的,而文件描述符0、1、2缺
省都和终端关联。如果希望命令从文件中读取标准输入或者希望命令的标准输出写到文件而不是屏幕,就需要
使用文件重定向。
2) 重定向标准输出
① CMD > filename : 把CMD命令的标准输出重定向到一个文件中(如果文件存在,其内容将被覆盖)。
② CMD >> filename : 把CMD命令的标准输出重定向到一个文件中(追加文件尾部)。
③ > myfile : 创建一个长度为0的空文件,如果文件存在清空该文件。
《LINUX与UNIX SHELL编程指南》读书笔记 第 11 页,共 58 页
> // 清空日志文件
⑤ CMD > filename实际上是和 CMD 1> filename等效,CMD >> filename和CMD 1>> filename等效。
3) 重定向标准输入
① CMD < filename : 以filename文件作为CMD命令的标准输入。
② CMD << DELIMITER : 从标准输入中读入输入,直至遇到DELIMITER分界符。(here-document)
③ 举例: sort < // 对文件进行排序(sort)
④ CMD < filename实际上是和 CMD 0< filename等效,CMD << filename和CMD 0<< filename等效。
4) 重定向标准错误
① CMD 2 > filename : 把CMD命令的标准错误重定向到一个文件中(如果文件存在,其内容将被覆盖)。
② CMD 2 >> filename : 把CMD命令的标准错误重定向到一个文件中(追加文件尾部)。
③ 举例: find / -name "*.tmp" -exec rm -rf {} ; 2>/dev/null // 把命令的错误消息输出丢弃
5) 结合使用标准输出和标准错误
① CMD 1> file1 2> file2 : 将输出重定向到file1中,并把标准错误重定向到file2中。
② CMD < file1 > file2 : 以file1文件作为CMD命令的标准输入,以file2文件作为标准输出。
③ 举例: find / -name "*.tmp" -print 1> 2> // 把find的搜索结果写到文件中,而把find
命令的错误信息(比如没有足够权限搜索某些目录)写到文件中
cat < > // 实际是将的内容写到,等效于文件复制
6) 合并标准输出和标准错误
① CMD > filename 2>&1 : 把标准输出和标准错误一起重定向到一个文件中
② CMD >> filename 2>&1 : 把标准输出和标准错误一起重定向到一个文件中(追加)
③ 举例: grep "standard" * > 2>&1 // 在当前目录下所有文本文件中搜索字符串"standard"
④ CMD > filename 2>&1 实际上可以看作2部分,"> filename"(重定向标准输出)和"2>&1"(把标准错误重定向
到标准输出)。
7) 在使用一些接受文件名为参数的命令时,有时命令会把文件描述符当成是文件名参数而报错。一般文件描述
符和重定向符号之间留有不要有空格。
第6章 命令执行顺序
1.使用"&&"
1) 命令1 && 命令2
2) &&左边的命令1返回真(即返回0,成功被执行)后,&&右边的命令2才能够被执行
3) 举例: cp /apps/bin /apps/dev/bin && rm -r /apps/bin // 如果复制操作完成,那么执行删除操作
《LINUX与UNIX SHELL编程指南》读书笔记 第 12 页,共 58 页
2.使用"||"
1) 命令1 || 命令2
2) 如果||左边的命令1未执行成功,那么就执行||右边的命令2
3) 举例: cp file1 file2 || echo "if seeing this,cp failed." // 如果复制失败,就打印信息
3.用"()"和"{}"将命令结合在一起
1) ( 命令1;命令2;... ) : 当前shell中执行一组命令
2) { 命令1;命令2;... } : 类上,相应的命令将在子shell而不是当前shell中作为一个整体被执行。只有在"{ }"中
所有命令的输出作为一个整体被重定向时,其中的命令才被放到子shell中执行,否则仍然在当前shell执行。
3) ()、{} 一般和&&或||一起使用
eg: cp file1 file2 || (echo "cp failed" | mail zqf; exit) // 当文件file1很大时,复制需要花 费很多时间,如
果复制过程中出错,将会发送一个邮件给用户,然后退出当前shell
4) 在编写shell脚本时,使用"&&"和"||",可根据前面命令的返回值来控制其后面命令的执行,对构造判断语句
非常有用。
《LINUX与UNIX SHELL编程指南》读书笔记 第 13 页,共 58 页
第7章 正则表达式(RE)介绍
1.当从一个文件或命令输出中抽取或过滤文本时,可以使用正则表达式(RE,regular expressions),正则表达式
是一些特殊或不很特殊的字符串模式的集合。正则表达式由一些特殊字符或进行模式匹配操作时使用的元字符
组成,当然也可以使用规则字符。
2.使用句点"."匹配单字符
1) . : 匹配任意单ASCII字符,可以为字母,或为数字。
2) 举例: ..XC..匹配deXC1t、23XCdf等,.w..w..w.匹配rwxrw-rw-
3.在行首以^匹配字符串或字符序列
1) ^ : 允许在一行的开始匹配字符或单词。
2) 举例: ^.01匹配0011cx4、c01sdf等,^d匹配drwxr-xr-x、drw-r--r--等
4.在行尾以$匹配字符串或字符
1) $ : 在行尾匹配字符串或字符,$符号放在匹配单词后。
2) 举例: trouble$ 匹配以单词trouble结尾的所有行
^$匹配所有空行
5.使用*匹配字符串中的单字符或其重复序列(与文件名置换中的"*"不一样)
1) * : 一个单字符后紧跟*,匹配0个或多个此单字符。
2) 举例: compu*t将匹配字符u一次或多次,即匹配computer computing compuuute等
1033* 可以匹配 101333 10133 1013444等
3) 在正则表达式中使用"*",有时会产生非预期的结果。
6.使用屏蔽一个特殊字符的含义
1) : 用来屏蔽一个元字符的特殊含义。因为有时在shell中元字符有特殊含义。可以使其失去应有意义。
2) 举例: 在正则表达式中匹配以*.pas结尾的所有文件: *.pas$
7.使用[]匹配属于一个范围或集合单个字符
1) [ ] : 匹配"[ ]"内的字符。可以是一个单字符,也可以是字符序列。可以使用"-"表示括号"[ ]"内字符序列范围,
如用[1-5]代替[12345]。可以用逗号","分隔括号"[]"内的字符。
2) 当"^"符号当直接靠着"[",意指否定或不匹配括号"[]"里内容
3) 举例: [0-9]匹配任意一个数字;[a-z]匹配任意一个小写字母;[0-9A-Za-z]匹配任意字母或数字;
[C,c]omputer匹配Computer和computer;[^a-zA-Z]匹配任一非字母型字符
《LINUX与UNIX SHELL编程指南》读书笔记 第 14 页,共 58 页
1) pattern{n} : 匹配模式pattern出现n次的情形。
2) pattern{n,} : 匹配模式pattern最少出现n次的情形。
3) pattern{,m} : 匹配模式pattern最多出现m次的情形。
4) pattern{n,m} : 匹配模式pattern出现次数在n与m之间的情形。
5) 举例: A{2}B 匹配的值为AAB
A{2,}B 匹配的值可以是AAB或AAAAAB,但不能匹配AB
A{2,4}B 匹配的值可以是AAB、AAAB、AAAAB,但不能匹配AB或AAAAAB等
[0-9]{4}CX[0-9]{4} 匹配数字出现4次后跟CX,最后是数字出现4次的情形
6) 实际上真正的格式是 {n} {n,} {,m} {n,m},只不过对"{"和"}"应用了Esacpe字符""。
9.经常使用的正则表达式举例
[Ss]igna[lL] 匹配单词signal、signaL、Signal、SignaL
[Ss]igna[lL]. 同上,但加一句点
^USER$ 只包含USER的行
. 带句点的行
^d..x..x..x 对对用户、用户组及其他用户、组成员有可执行权限的目录
^[^l] 排除符号链接文件后的文件目录列表(即不是以"l"开始的行)
[yYnN] 大写或小写y或n
^.*$ 匹配行中任意字符串
^......$ 包括6个字符的行
[a-zA-Z] 任意单个字母
[a-z]* 至少一个小写字母
[^0-9$] 非数字或美元符号
[123] 1到3中一个数字
^q 以^q开始行
^.$ 仅有一个字符的行
^.[0-9][0-9] 以一个句点和两个数字开始的行
[0-9]{2}-[0-9]{2}-[0-9]{4} 日期格式dd-mm-yyyy
[0-9]{3}.[0-9]{3}.[0-9]{3}.[0-9]{3} 类IP地址格式
.* 匹配任意多个字符
10.在shell编程中,一段好的脚本与完美的脚本间的差别之一,就是要熟知正则表达式并学
会使用它们。有很多可以处理文本的程序,比如grep、awk、sed等都使用正则表达式。
第8章 grep家族
《LINUX与UNIX SHELL编程指南》读书笔记 第 15 页,共 58 页
1) grep是使用最广泛的命令之一,用来对文本文件内容按行进行模式匹配查找。如果找到匹配模式的行,
grep将打印包含模式的行。
2) grep有三种变形:
① Grep : 标准grep命令,主要讨论此格式。
② Egrep: 扩展grep,支持基本及扩展的正则表达式。
③ Fgrep: 快速grep,允许查找字符串而不是一个模式。这里的"快速"并不是指速度快。
的用法
1) grep Usage: grep [OPTION] regular_expressions [filename1 ...]
① regular_expressions : 是正则表达式,一般用单引号把正则表达式括起来。当然,也可以不使用正则表达式
而使用字符串,使用字符串时一般用双引号把字符串括起来。
② filename1 ... : 文件名列表,grep将对这些指定的文件的内容进行匹配查找,如果文件名列表省略,grep将
从标准输入读取要匹配查找的内容。
2) grep的常用选项:
-c 只输出匹配的行的总数(count)。
-i 不区分大小写(只适用于单字符)。
-h 查询多个文件时,不显示文件名。
-l 查询多个文件时,只输出包含匹配模式的文件的文件名。
-n 显示匹配的行及行号。
-s 不显示不存在或无匹配文件等错误信息(silence)。
-v 只显示不包含匹配模式的行。
应用举例
1) 查询多个文件,可以使用*。比如:
grep "sort" *.doc // 在所有以doc为后缀的文件中查找字符串"sort"
grep "linux" * // 在当前目录下的所有文件中查找字符串"linux"
2) 精确匹配,可以在要匹配的字符串后加>。
grep "48>" data.f // 可以匹配48、1248、c48 This等而不能匹配481、c480
3) 反转匹配
ps aux | grep "httpd" | grep -v "grep" // 查看正在运行的httpd进程
4) 匹配空行
grep -n '^$' myfile // 打印文件myfile中空行的行号
grep -v '^$' myfile // 去除文件myfile中的空行
《LINUX与UNIX SHELL编程指南》读书笔记 第 16 页,共 58 页
1) 常见的匹配模式的类名形式:
[[:upper:]] 等价于 [A-Z]
[[:lower:]] 等价于 [a-z]
[[:digit:]] 等价于 [0-9]
[[:alnum:]] 等价于 [0-9a-zA-Z]
[[:space:]] 等价于 空格或tab键
[[:alpha:]] 等价于 [a-zA-Z]
2) 举例: grep '5[[:upper:]][[:upper:]]' data.f // 可以匹配包括5AP196、5DF540的行
5.可以把要匹配的模式写到一个文件中,然后使用 -f 选项,将该未能传给grep。
eg: eg: egrep -f grappats data.f // 要匹配的模式存放在文件grappats中
6.可以在grep的模式字符串中使用(|)符号,意即“|”符号两边之一或全部,可以使用任意多"|",可同时使用^符号排
除字符串
eg: who | grep '(zqf|zqc|zqx)' // 查看是否zqf zqc zqx三者中是否有在线的
7.如果传递给grep的文件名参数是不是一个普通文件而是一个目录的话,要使用"-d"选项。
1) Usage: grep -d [ACTION] directory_name
2) ACTION : ACTION用来指定对作为输入文件的目录文件的处理方式,ACTION有3个可选值:
① read : 把目录文件当作普通文件来读取,是选项省略时的默认方式。
② skip : 目录将被忽略而跳过
③ recurse : grep以递归的方式读取目录下的每一个文件。等同于选项 "-r" 。
3) 举例: grep -rl "eth0" /etc // 查看/etc目录中于"eth0"有关的文件的文件名
第9章 AWK介绍
有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk。
语言的最基本功能是在文件或字符串中基于指定规则来分解抽取信息,也可以基于指定的规则来输出数
据。完整的awk脚本通常用来格式化文本文件中的信息。
2.三种方式调用awk
1) awk [opion] 'awk_script' input_file1 [input_file2 ...]
awk的常用选项option有;
① -F fs : 使用fs作为输入记录的字段分隔符,如果省略该选项,wak使用环境变量IFS的值
② -f filename : 从文件filename中读取awk_script
③ -v var=value : 为awk_script设置变量
《LINUX与UNIX SHELL编程指南》读书笔记 第 17 页,共 58 页
3) 将所有的awk_script插入一个单独脚本文件,然后调用: awk -f wak脚本文件 input_file(s)
3. awk的运行过程
1) awk_script的组成:
① awk_script可以由一条或多条awk_cmd组成,两条awk_cmd之间一般以NEWLINE分隔
② awk_cmd由两部分组成: awk_pattern { actions }
③ awk_script可以被分成多行书写,必须确保整个awk_script被单引号括起来。
2) awk命令的一般形式:
awk ' BEGIN { actions }
awk_pattern1 { actions }
............ > awk_script
awk_patternN { actions } /
END { actions } /
' inputfile
其中 BEGIN { actions } 和 END { actions } 是可选的。
3) awk的运行过程:
① 如果BEGIN 区块存在,awk执行它指定的actions。
② awk从输入文件中读取一行,称为一条输入记录。(如果输入文件省略,将从标准输入读取)
③ awk将读入的记录分割成字段,将第1个字段放入变量$1中,第2个字段放入$2,以此类推。$0表示整
条记录。字段分隔符使用shell环境变量IFS或由参数指定。
④ 把当前输入记录依次与每一个awk_cmd中awk_pattern比较,看是否匹配,如果相匹配,就执行对应的
actions。如果不匹配,就跳过对应的actions,直到比较完所有的awk_cmd。
⑤ 当一条输入记录比较了所有的awk_cmd后,awk读取输入的下一行,继续重复步骤③和④,这个过程一直
持续,直到awk读取到文件尾。
⑥ 当awk读完所有的输入行后,如果存在END,就执行相应的actions。
4) iput_file可以是多于一个文件的文件列表,awk将按顺序处理列表中的每个文件。
5) 一条awk_cmd的awk_pattern可以省略,省略时不对输入记录进行匹配比较就执行相应的actions。一条
awk_cmd的actions也可以省略,省略时默认的动作为打印当前输入记录(print $0) 。一条awk_cmd中的
awk_pattern和actions不能同时省略。
6) BEGIN区块和END区块别位于awk_script的开头和结尾。awk_script中只有END区块或者只有BEGIN
区块是被允许的。如果awk_script中只有BEGIN { actions } ,awk不会读取input_file。
7) awk把输入文件的数据读入内存,然后操作内存中的输入数据副本,awk不会修改输入文件的内容。
《LINUX与UNIX SHELL编程指南》读书笔记 第 18 页,共 58 页
_pattern
awk_pattern模式部分决定actions动作部分何时触发及触发actions。awk_pattern可以是以下几种类型:
1) 正则表达式用作awk_pattern: /regexp/
① awk中正则表达式匹配操作中经常用到的字符:
^ $ . [] | () * // 通用的regexp元字符
+ : 匹配其前的单个字符一次以上,是awk自有的元字符,不适用于grep或sed等
? : 匹配其前的单个字符1次或0次,是awk自有的元字符,不适用于grep或sed等
② 举例:
awk '/ *$0.[0-9][0-9].*/' input_file
2) 布尔表达式用作awk_pattern,表达式成立时,触发相应的actions执行。
① 表达式中可以使用变量(如字段变量$1,$2等)和/regexp/
② 布尔表达式中的操作符:
关系操作符: < > <=
>= == !=
匹配操作符: value ~ /regexp/
value !~ /regexp/
如果value匹配/regexp/,则返回真
如果value不匹配/regexp/,则返回真
举例: awk '$2 > 10 {print "ok"}' input_file
awk '$3 ~ /^d/ {print "ok"}' input_file
③ &&(与) 和 ||(或) 可以连接两个/regexp/或者布尔表达式,构成混合表达式。!(非) 可以用于布尔表达式或者
/regexp/之前。
举例: awk '($1 < 10 ) && ($2 > 10) {print "ok"}' input_file
awk '/^d/ || /x$/ {print "ok"}' input_file
④ 其它表达式用作awk_script,如赋值表达式等
eg: awk '(tot+=$6); END{print "total points :" tot }' input_file
s
actions就是对awk读取的记录数据进行的操作。actions由一条或多条语句或者命令组成,语句、命令之间用
分号(;)分隔。actions中还可以使用流程控制结构的语句。
1) awk的命令:
① print 参数列表 : print可以打印字符串(加双引号)、变量和表达式,是awk最基本的命令。参数列表要用逗
号(,)分隔,如果参数间用空格分隔,打印出时参数值之间不会有空格。
② printf ([格式控制符],参数) : 格式化打印命令(函数),语法与C语言的printf函数类似。
③ next : 强迫awk立刻停止处理当前的记录,而开始读取和处理下一条记录。
④ nextfile : 强迫awk立刻停止处理当前的输入文件而处理输入文件列表中的下一个文件
⑤ exit : 使awk停止执行而跳出。如果有END 存在,awk会去执行END 的actions。
2) awk的语句: awk的语句主要是赋值语句,用来给变量赋值。
// 分号不能省略
awk 'tot+=$6 {print $0} END{print "total points :" tot }' input_file // 与上面等效
《LINUX与UNIX SHELL编程指南》读书笔记 第 19 页,共 58 页
举例: awk 'BEGIN {x=1 ; y=3 ; x=y ; print "x=" x " ; y=" y }'
② 把一个表达式的值赋值给变量。表达式一般是数值表达式,也可以是其它表达式。
数值表达式: num1 operator num2
operator可以是: +(加) -(减) *(乘) /(除) %(取模) ^(求幂)
当num1或者num2是字符串而是不是数字时,无论是否加有双引号,awk都视其值为0
条件选择表达式: A?B:C (A为布尔表达式,B和C可以是表达式或者直接值)
当布尔表达式A的值为真时,整个表达式的值为B,A的值为假时,整个表达式的值为C
举例: awk 'BEGIN {x=3 ; x+=2 ; y=x+2 ; print "x=" x " ; y=" y }'
awk 'BEGIN {x=3 ; y=x>4?"ok":4 ; print "x=" x " ; y=" y }'
③ 为了方便书写,awk也支持C语言语法的赋值操作符: += -= *= /= %= ^= ++ --
3) 流程控制结构 (基本上是使用C语言的语法)
其中condition一般为布尔表达式,body和else-body是awk语句块。
① if (condition) {then-body} [else {else-body}]
② while (condition) {body}
③ do {body} while (condition)
④ for (initialization; condition; increment) {body}
与C语言的for结构的语法相同。
⑤ break
⑥ continue
的变量
在awk_script中的表达式中要经常使用变量。不要给变量加双引号,那样做,awk将视之为字符串。awk的
变量基本可以分为两类:
1) awk内部变量: awk的内部变量用于存储awk运行时的各种参数,这些内部变量又可以分为:
① 自动内部变量: 这些变量的值会随着awk程序的运行而动态的变化,在awk_script中改变这些变量的值是
没有意义的(即不应该被赋值)。常见的有:
NF
NR
: 当前输入字段的字段数
: 对当前输入文件而言,已经被awk读取过的记录(行)的数目。
: 已经被awk读取过的记录(行)的总数目。当输入文件只有一个时,FNR和NR是一致的。
: 当前输入文件的文件名。
: 命令行参数个数。(不包括选项和awk_script,实际就是输入文件的数目加1)
: 当前被处理的文件在数组ARGV内的索引( 实际上ARGV[1]就是第一个输入文件 )
: 跳出包含它的for、while、do-while 循环
: 跳过for、while、do-while循环的body的剩余部分,而立刻进行下一次循环的执行。
FNR
FILENAME
ARGC
ARGIND
举例: awk '{print NR,NF,$0} END {print FILENAME}' input_file
② 字段变量($0 $1 $2 $3 ...): 当awk把当前输入记录分段时,会对这些字段变量赋值。和内部变量类似,在
awk运行过程中字段变量的值是动态变化的。不同的是,修改这些字段变量的值是有意义的,被修改的字段值
可以反映到awk的输出中。
可以创建新的输出字段,比如,当前输入记录被分割为8个字段,这时可以通过对变量 $9 (或$9之后的字
段变量)赋值而增加输出字段,NR的值也将随之变化。
《LINUX与UNIX SHELL编程指南》读书笔记 第 20 页,共 58 页
举例: pwd |awk -F/ '{print $NF}' // print $NF 打印输入记录的最后一个字段
awk '{x=2;print $x}' input_file // 打印输入记录的第2个字段
③ 其它内部变量: 可以修改这些变量。常见的有:
FS : 输入记录的字段分隔符(默认是空格和制表符)
: 数字的输出格式(默认是 %.6g)
OFS : 输出记录的字段分隔符(默认是空格)
OFMT
RS : 输入记录间的分隔符(默认是NEWLINE)
: 命令行参数数组
: 存储系统当前环境变量值的数组,它的每个成员的索引就是一个环境变量名,而对应的值就
ORS : 输出记录间的分隔符(默认是NEWLINE)
ARGV
ENVIRON
是相应环境变量的值。可以通过给ENVIRON数组的成员赋值而改变环境变量的值,但是新值只在awk_script
内有效。eg: ENVIRON["HISTSIZE"]=500
举例: cat /etc/passwd | awk 'BEGIN { FS=":" } {print "User name: "$1,"UID: "$4}'
2) 自定义变量
1) 定义变量: varname=value (自定义变量不需先声明后使用,赋值语句同时完成变量定义和初始化)
2) 在表达式中出现不带双引号的字符串都被视为变量,如果之前未被赋值,默认值为0或空字符串。
3) 向命令行awk程序传递变量的值:
① Usage: awk 'awk_script' awkvar1=value1 awkvar2=value2 .... input_file
eg: awk '{if ($5 < ARG) print $0 }' ARG=100 input_file
② awkvar可以是awk内置变量或自定义变量。
③ awkvar的值将在awk开始对输入文件的第一条记录应用awk_script前传入。如果在awk_script中已经对
某个变量赋值,那么在命令行上传人到该变量的值就会无效(实际上是awk_script中的赋值语句覆盖了从命令
行上传入的值)。
④ 在awk脚本程序中不能直接使用shell的变量。通过使用下面的语法可达到这样的效果。
awk 'awk_script' awkvar1=shellvar1 awkvar2=shellvar2 .... input_file
eg: awk '{if (v1 == "root") {print "User name is root!"}}' v1=$USER input_file
⑤ 可以向awk脚本传递变量的值,与上面的类似。
awk_script_file awkvar1=value1 awkvar2=value2 ... input_file
的内置函数
可以在awk_script的任何地方使用awk函数。和awk变量一样,awk函数可以分为内置函数和自定义函数。
1) 常见awk内置数值函数
int(x) : 求出x 的整数部份,朝向0 的方向做舍去。eg: int(3.9)是3,int(-3.9) 是-3。
sqrt(x) : 求出x 正的平方根值。eg: sqrt(4)=2
exp(x) : 求出x 的次方。eg: exp(2) 即是求e*e 。
log(x) : 求出x 的自然对数。
sin(x) : 求出x 的sine 值,x 是弪度量。
《LINUX与UNIX SHELL编程指南》读书笔记 第 21 页,共 58 页
atan2(y,x) : 求y/x 的arctangent 值,所求出的值其单位是弪度量。
rand() : 得到一个随机数(平均分布在0和1之间)。每次执行gawk,rand从相同的seed生成值。
srand(x) : 设定产生随机数的seed为x。如果在第二次运行awk程序时你设定相同的seed值,你将再度
得到相同序列的随机数。如果省略引数x,例如srand(),则当前日期时间会被当成seed。这个方法可使得随
机数值是真正不可预测的。
srand() : 其值是当次awk_script运行过程中前次srand(x)的设定的seed值x,。
2) 常见awk内置字符串函数
index(in, find) : 返回字符串in中字符串find第一次出现的位置(索引从1开始),如果在字串in中找不到字符
串find,则返回值为0。eg: print index("peanut","an") 会印出3。
length(s) : 求出字符串s的字符个数。eg: length("abcde") 是5。
match(s,r) : 返回模式字符串r在字符串s的第一次出现的位置,如果s不包含r,则返回值0。
sprintf(fmt,exp1,...) : 和printf类似印出,是sprintf不是打印而是返回经fmt格式化后的exp。
eg: sprintf("pi = %.2f (approx.)",22/7) 传回的字串为"pi = 3.14 (approx.)"
sub(p, r,t) : 在字符串t中寻找符合模式字符串p的最靠前最长的位置,并以字符串r代替最前的p。
eg: str = "water, water"sub(/at/, "ith",str) 结果字符串str 会变成"wither, water"
gsub(p, r, t) : gsub与sub类似。不过时在字符串t中以字符串r 代替所有的p。
eg: str="water, water" ; gsub(/at/, "ith",str) 结果字符串str会变成"wither,wither"
substr(str, st, len) : 传回str的子字符串,其长度为len字符,从str的第st个位置开始。如果len没有
出现,则传回的子字符串是从第st个位置开始至结束。
eg: substr("washington",5,3) 传回值为"ing"
substr("washington",5) 传回值为"ington"
split(s,a,fs) : 在分隔符fs为分隔符将字符串s分隔成一个awk数组a,并返回a的下标数。
eg: awk 'BEGIN{print split("123#456#789",myarray,"#")}' 将打印 3 。
tolower(str) : 将字符串str的大写字母改为小写字母。
eg: tolower("MiXeD cAsE 123") 传回值为"mixed case 123"
toupper(str) : 将字符串string 的小写字母改为大写字母。
eg: toupper("MiXeD cAsE 123")传回值为"MIXED CASE 123"
3) 常见awk内置系统函数
close(filename) : 将输入或输出的文件filename 关闭。
system(command) : 此函数允许调用操作系统的指令,执行完毕後将回到awk程序。
eg: awk 'BEGIN {system("ls")}'
8 自定义函数
复杂的awk常常可以使用自己定义的函数来简化。调用自定义的函数与调用内置函数的方法一样。
1) 自定义函数定义的格式: 自定义函数可以在awk程序的任何地方定义。
function fun_name (parameter_list) {
body-of-function
// parameter_list是以逗号分隔的参数列表
// 函数体,是awk语句块
《LINUX与UNIX SHELL编程指南》读书笔记 第 22 页,共 58 页
2) 举例:
awk '{ print "sum =",SquareSum($1,$2) }
function SquareSum(x,y) { sum=x*x+y*y ; return sum } '
的数组
数组使用前,不必预先定义,也不必指定数组元素个数。
1) 访问数组的元素。经常使用循环来访问数组元素,下面是一种循环类型的基本结构:
for (element in array_name ) print array_name[element]
2) 举例: awk 'BEGIN{print split("123#456#789",mya,"#") ; for (i in mya) { print mya[i] }} '
10.其他
1) 为了避免碰到awk错误,可以总结出以下规律:
① 确保整个awk_script用单引号括起来。
② 确保awk_script内所有引号成对出现。
③ 确保用花括号括起动作语句,用圆括号括起条件语句。
④ 可能忘记使用花括号,也许你认为没有必要,但awk不这样认为,将按之解释语法。
⑤ 如果使用字符串,一定要保证字符串被双引号括起来(在模式中除外)。
2) 在awk中,设置有意义的域名是一种好习惯,在进行模式匹配或关系操作时更容易理解。一般的变量名设
置方式为name=$n。(这里name为调用的域变量名, n为实际域号。)
3) 通常在BEGIN部分给一些变量赋值是很有益的,这样可以在awk表达式进行改动时减少很多麻烦。
4) awk的基本功能是根据指定规则抽取输入数据的部分内容并输出,另一个重要的功能是对输入数据进行分
析运算得到新的数据并输出,这是通过在awk_script中对字段变量($1、$2、$3...)从新赋值或使用更大的字段
变量$n(n大于当前记录的NF)而实现的。
5) 使用字符串或正则表达式时,有时需要在输出中加入一新行或查询一元字符。这时就需要字符串屏蔽序列。
awk中经常使用的屏蔽序列有:
b 退格键 t tab键 f 走纸换页 ddd 八进制值 n 新行 r 回车键
c 任意其他特殊字符。eg: 为反斜线符号
6) awk的输出函数printf,基本上和C语言的语法类似。
① 格式: printf ("输出模板字符串",参数列表)
② 参数列表是以逗号分隔的列表,参数可以是变量、数字值或字符串。
③ 输出模板字符串的字符串中必须包含格式控制符,有几个参数就要求有几个格式控制符。模板字符串中可
以只有格式控制符而没有其它字符。
④ 格式控制符: %[-][width][.prec]fmt
%
-
: 标识一个格式控制符的开始,不可省略。
: 表示参数输出时左对齐,可省略。
《LINUX与UNIX SHELL编程指南》读书笔记 第 23 页,共 58 页
.prec : prec是一个数值,表示最大字符串长度或小数点右边的位数,可省略。
fmt : 一个小写字母,表示输出参数的数据类型,不可省略。
⑤ 常见的fmt : c ASCII字符
d 整数
e 浮点数,科学记数法
f 浮点数,如 123.44
g 由awk决定使用哪种浮点数转换e或f
o 八进制数
s 字符串
x 十六进制数
⑥ 举例: echo "65" | awk '{ printf ("%cn",$0) }' // 将打印 A
awk 'BEGIN{printf "%.4fn",999}' //将打印 999.0000
awk 'BEGIN{printf "2 number:%8.4f%8.2f",999,888}' // 将打印 2 number:999.0000 888.000
第10章 sed用法介绍
是一个非交互性文本流编辑器
1) sed编辑文件或标准输入导出的文本拷贝。标准输入可能是来自键盘、文件重定向、字符串或变量,或者是
一个管道的文本。可以在命令行输入sed命令,也可以在一个文件中写入命令,然后调用sed。
2) sed操作的只是一个输入文件在内存内的一个副本,对副本内容进行编辑改动,如果没有重定向到一个文
件,将编辑修改的结果输出到屏幕。和awk一样,sed不会修改输入文件的内容。
3) 因为sed是一个非交互性编辑器,sed使用一种行定位模式来定位哪些文本行将要被编辑修改。
4) sed从输入数据中读取一行,将之拷贝到一个编辑缓冲区,然后读命令行或脚本的第一条命令,并使用这些
命令中指定的定位模式来确定是否编辑和如何编辑它。重复此过程直到命令结束。
2.调用sed的三种方式
1) 在命令行键入命令: sed [选项] 'sed_cmd' input_file
① sed常用选项:
-n : sed默认在将下一行读入行缓冲区中之前,自动输出行缓冲区中的内容。此选项可以关闭自动输出。
-e : sed如果要在命令行上调用多于一条的sed_cmd,必须在每条sed_cmd前加"-e"选项
eg: sed -e 'sed_cmd1' -e 'sed_cmd2' -e 'sed_cmd3' input_file
② sed_cmd的格式: '[address]sed_edit_cmd' (一般用单引号括起来)
address : sed的行定位模式,用于指示将要被sed编辑的行。如果省略,sed将编辑所有行。
sed_edit_cmd : sed对被编辑行将要进行的编辑操作。
③ input_file : 指定sed的输入文件,可以是一个文件列表。如果省略,sed将从标准输入读取输入。
《LINUX与UNIX SHELL编程指南》读书笔记 第 24 页,共 58 页
3) 将sed命令插入脚本文件,使sed脚本文件可执行,在控制台下通过直接键入脚本文件名来执行。
sed脚本文件格式:
#!/bin/sed -f
sed_cmd1
sed_cmd2
...
_cmd的address 用于定位要编辑的行
x : x为一行号。如 5
x,y : 表示行号范围从x到y。如 2,5 表示从第2行到第5行
/pattern/ : 查询包含模式的行。如 /disk/或/[a-z]/
/pattern/pattern/ : 查询包含两个模式的行。例如 /disk/disks/
/pattern/,x : 在给定行号上查询包含模式的行。如 /ribbon/,3
x,/pattern/ : 通过行号和模式查询匹配行。如 3,/vdu/
x,y! : 查询不包含指定行号x和y的行。如 1,2!
4.常见的sed_edit_cmd(sed的行编辑命令)
1) p : 打印匹配行
eg: sed -n '1,3p' // 只打印文件的第1-3行
sed -n '$p' // 只打印文件的最后一行
2) = : 显示文件匹配行行号
eg: sed -n '/music/=' //打印文件中包含"music"字符串的行的行号
3) a :在指定行(不能是多行范围)后附加N行新文本并显示新文本,多用于脚本。
格式如: [address]a // 符号""是必须的
textline1 // 如要附加多行,要在行尾加符号"",表示换行
textline2
.....
textlineN
#!/bin/sed -f
/company/a
4) i : 在指定行前插入新文本并显示新文本,格式同a
5) d : 删除被定位的行
eg: sed '3,$d' // 删除文件的第3到最后一行
// 被附加的多行文本的最后一行不加""
// sed会把它看作是附加命令的结尾
// 把其下一行当作一条新的sed_cmd
// 调用脚本: ./
eg: $ cat // 查看sed脚本文件的内容
The suddenly it happend.
《LINUX与UNIX SHELL编程指南》读书笔记 第 25 页,共 58 页
7) s : 用模式replacement替换被定位行中的oldpattern。
① 格式: [address]s/oldpattern/replacement/[gpw]
② 替换选项如下:
g : 缺省情况下只替换行中第一次出现的oldpattern,使用g选项替换行全局所有出现的oldpattern。
p : 显示被替换后的行,省略p并使用了sed的"-n"选项,将看不到任何输出。
w filename : 将被替换后的行内容写到文件filename中。
eg: sed -n 's/night/NIGHT/gp' // 只显示被替换过了的行
sed -n 's/night/NIGHT/' // 在屏幕上没有任何显示
sed 's/night/NIGHT/' // 显示所有行(被替换和没有替换的行)
sed 's/night/NIGHT/w fdt' // 同上,还把被替换的行内容写到文件fdt中
sed 's/night/NIGHT/' > fdt // 把所有行写入文件fdt
③ 如果要附加或修改一个字符串,可以使用&命令,&命令保存模式oldpattern以便重新调用它,然后把它放
在替换字符串里面。
eg: sed -n 's/nurse/Hello &/p' // 等效于在nurse前插入"Hello "。
8) r : 从另一个文件中读文本附加到指定的行后,并显示读入的文本内容。
eg: sed '/company/r ' // 在显示的内容中间显示的内容
sed -n '/company/r ' //只显示的内容
9) w : 写文本到一个文件
eg: sed '1,2 w filedt' // 将文件的第1-2行写入到文件filedt中
10) q : 读取到被[address]定位的行后后退出sed,以便执行其他处理脚本。
11) l : 显示被定位行中所有字符,包括控制字符(非打印字符)。
eg: sed '1,$l' // 显示文件中所有字符。可以在每行行尾看到一个"$"字符
12) { } : 在被定位的行上执行的命令组。
eg: sed -n '{s/night/Night/;p}' 与 sed '{s/night/Night/}' 等效
13) n : 从另一个文件中读文本下一行,并附加在下一行
5.如何输入控制字符(如回车、Esc、F1等),以输入回车(^M)为例:
1) 按下Ctrl键和v键
2) 释放v键,然后按下^键(此过程中Ctrl键保持按下不放)
3) 释放按下的两个键
4) 按下对应的功能键(Enter键)即可
支持shell变量名替换,即在sed_cmd中可以使用shell变量。在sed命令中使用shell变量时,应使用
双引号,否则不能得到期望的结果。
《LINUX与UNIX SHELL编程指南》读书笔记 第 26 页,共 58 页
7.一些sed一行命令集。([]表示空格, [ ]表示tab键)
's/.$//g' 删除以句点结尾行
'/abcd/d' 删除包含abcd的行
's/[][][]*/[]/g' 删除一个以上空格,用一个空格代替
's/^[][]*//g' 删除行首空格
's/.[][]*/[]/g' 删除句点后跟两个或更多空格,代之以一个空格
'/^$/d’ 删除空行
's/^.//g' 删除第一个字符
's/^//g' 从路径中删除第一个/
's/[]/[]/[ ]/g’ 删除所有空格并用t a b键替代
'S/^[ ]//g’ 删除行首所有t a b键
8。如果使用sed对文件进行过滤,最好将问题分成几步,分步执行,且边执行边测试结果,这是执行一个复
杂任务的最有效方式。
第11章 合并与分割
用于文本文件数据内容排序
1) usage: sort [sort选项] [input_file ....]
2) sort命令的操作可以分为3种模式:
① 排序模式: 对输入文件进行排序,是默认的模式。
② 合并模式: 对两个已排序的文件进行合并。需要指定"-m"选项。
③ 检查模式: 测试给定的输入文件是否已排序。需要指定"-c"选项。
eg: sort -c // 如果已排序,则无任何显示。如果未排序,则会给出提示
3) sort有许多不同的选项,这些选项基本可以分为三类:
① sort的操作模式选项: 就是用于指定sort工作模式的选项,只有"-c"和"-m"两个。
② sort的数据排序选项: 这些选项将影响输出行的排列顺序,可以是针对整体或特殊键值字段设定的。
③ sort的字段设定与输出选项: 与输出和字段有关的选项。
的常用数据排序选项
1) -n : 当指定位置上是数字字符时,按数值大小来排序,而不是逐字符比较。
2) -b : 忽略前置空白。
3) -r : 颠倒输出排序的结果(即逆序输出)。
4) -d : 在排序时忽略所有除英文字母、数字及空白之外的字符。
5) -f : 在排序时将字母大小写视为相同。
《LINUX与UNIX SHELL编程指南》读书笔记 第 27 页,共 58 页
7) -M : 对表示月份的三个大写字母进行比较,"无效名称" < "JAN" < "FEB" <...< "DEC"。
的常用字段设定与输出选项
如果没有使用任何字段设定选项,sort默认对整行的内容做排序。如果希望针对行中某一特定的字段内容做排
序,就必须知道如何指定字段的分隔符以及指定适当的排序字段。
1) -o FILE : 指定排序结果的输出文件,输出文件可以时输入文件之一。
eg: sort -o // 把的排序结果写入
2) -t 分隔符 : 设定字段分隔符,如果省略此选项,sort使用shell环境变量IFS。
3) -u : 检查指定域的唯一性(不重复)(检查排序模式),或去除域重复的行(排序、合并模式下)。
4) -k pos1[,pos2] : 把pos1到pos2之间的内容当成一个字段来进行排序(域号pos1 ① 如果省略pos2,表示从pos1到行尾。 ② k选项的pos可以是"F[.C]"格式,即F指示使用第几个字段,C指示从字段开头算起第几个字符。 eg: sort -t: -k2,3n // 从第二个字段的第三个字符开始排序 ③ pos后可以附加任何数据排序选项字符"Mbdfinr"。 5) +POS : 使用由POS指定的域开始排序。POS和上面的pos用法类似,只是POS从0开始计数。 eg: sort -t, +3 +2 employee // 先以第4个字段为第一排序字段,以第3个字段第二排序字段 sort -t, -k4 -k3 employee // 与上面的等效 sort -t: +1,2n // 与使用"-k2,3n"选项等效 6) -POS : 排序时忽略由POS指定的域。不能单独使用,只能放在+POS选项之后使用。 eg: sort -t: +0 -2 +3 // 以第一个域开始排序,忽略第三个域,再使用第四个域排序 用于合并2个排序文件(将文件合并前,它们必须已被排序) 1) Usage:sort -m [-o 输出文件] [选项] file1 file2 2) sort默认使用第一个字段来进行合并排序。 1) uniq用来从一个文本文件中去除或禁止重复行。一般uniq假定输入文件已分类。但uniq并不强制要求如 此,也可以使用任何非排序文本,甚至是无规律行。 2) uniq不同于sort的-u选项,uniq认为持续不断重复出现的行(中间不包括其它文本)才是重复行。 3) uniq Usage: uniq [选项] [input_file [output_file]] 4) uniq常用选项: -u 只显示没有重复的行。不使用此选项时,uniq会把连续重复行的内容显示一次。 《LINUX与UNIX SHELL编程指南》读书笔记 第 28 页,共 58 页 -c 打印每一重复行出现次数。 -i 忽略字母的大小写 -fx x为数字(x=1.2..),先跳过x个域再开始比较,与"-x"等效。有的系统使用"-nx"选项。 -sx 跳过x个字符后再开始比较(x=1.2..),与"+x"等效。与"-fx"连用时,一般放在"-fx"之后。 5) 举例: uniq -f2 -s4 // 从文件行中的第3个字段第5字符开始执行 使用共同的字段连接文件 1) join Usage: join [选项] file1 file2 2) join程序主要用来连接两个文件的数据行,join在执行时会在输入文件中寻找具有相同join字段的输入行, 并把连接的结果输出到标准输出。 3) join的两个输入文件都应该已经对要join的字段作了递增排序,否则执行结果将会错误。 4) join默认使用每个输入文件文件行的第一个字段为join字段。输出行的字段间以一个空格隔开,每一个输出 行上包括join字段、file1内其余字段以及file2内的其余字段。 的常用选项 1) -ax : 将文件编号为x(x=1,2)的文件中未被匹配连接的行额外打印出来。 2) -o x.y[,x.y,...] : 在输出中只打印文件x的第y(y=)个字段。 3) -j m : 指定两个文件都用第m(m=)个字段作为join字段。 4) -j1 m 或 -1 m : 指定文件1使用第m(m=)个字段作为join字段。 5) -j2 m 或 -2 m : 指定文件2使用第m(m=)个字段作为join字段。 6) -t char : 指定char为输入输出字段的分隔符,省略时使用shell环境变量IFS。 7) -i : 忽略字母的大小写。 8) -vx : 只打印文件x(x=1,2)中未被匹配连接的行,而不打印连接的结果。 打印行中被选取的部分 1) cut命令主要用于选择性的打印输入文件行的部分内容。 2) cut usage: cut [options] input_file(s) 3) 输入文件可以是一个文件列表。如果没有指定输入文件,或设置为"-",将会使用标准输入为输入。 4) cut的常用选项: ① -d char : 指定char为输入行字段分隔符(预设使用shell环境变量IFS)。输出使用相同的域分隔符。 ② -f 字段列表 : 只打印在字段列表中的字段。用数字表示要打印的字段,列表可以使用"-"和","。数字都是从1 开始编号。"-m"表示1-m,"n-"表示从n到最末。 eg: cut -d: -f1,6 /etc/passwd // 打印系统中的用户名及其主(home)目录(即第1和第6个域) ③ -c 字符列表 : 用数字列表指定要剪切的字符位置,列表格式同②。 eg: who -u |cut -c1-8 // 打印有哪些用户正在使用系统 《LINUX与UNIX SHELL编程指南》读书笔记 第 29 页,共 58 页 1) paste Usage: paste [options] [file1 file2] 2) paste将两个输入文件的每一行连接成一个新行并输出。file1的行内容位于file2之前。 3) 缺省情况下, paste连接时,用空格或tab键分隔新行中不同文本,除非指定"-d"选项。 4) 常用选项: ① -d char : 指定char作为字段分隔符。例如用@分隔域,使用-d@。 ② -s : 将每个文件的内容作为一行输出,有n个输入文件就输出n行。 5) 没有指定输入文件而用"-"代替时,表示使用标准输入作为输入源。 eg: ls | paste -d" " - - - - - // 以每5个文件名为一行显示文件和目录 6) 粘贴两个不同来源的数据时,首先需应该将其分类(即要求已经排序),并确保两个文件行数相同。 将文件分段 1) split用来将大文件分割成小文件。有时文件越来越大,传送这些文件时,首先将其分割可能更容易。使用vi 或其他工具诸如sort时,如果文件对于工作缓冲区太大,也会存在一些问题。因此有时没有选择余地,必须将 文件分割成更小的文件。 2) split Usage: split [选项] input-filename [输出文件前缀] 3)常用选项: split的选项一般用来指定输出文件的尺寸,split预设为100行生成一个新的文件。 ① -x、-lx、--lines=x : 每x行生成一个新的输出文件 ② -b n、--bytes=n : 每n字节生成一个新的输出文件,可用后缀b k m表示以block KB MB为单位。 ③ --verbose : 每生成一个新的输出文件时,就打印一行信息到标准错误。 4) 输出文件前缀 : 默认每个生成的输出文件的格式为xaa xab..到..xzy xzz。文件前缀为x,aa ab..为文件名后 缀。可以指定文件名前缀。 5) 举例: split -3 // 将文件(共8行)分割成3个小文件xaa、xab、xac split -3 vdo // 将文件分割成3个小文件vdoaa、vdoab、vdoac 第12章 tr 用法 转换或删除字符 1) tr主要用来从标准输入中通过替换或删除操作进行字符转换,然后打印输出到标准输出。可以通过管道或重 定向标准输入来获得tr的输入数据。 2) tr对输入数据可以进行三种操作: 字符替换、压缩重复字符和删除字符。 《LINUX与UNIX SHELL编程指南》读书笔记 第 30 页,共 58 页 4) tr有4个常用选项(c d s t),下面将作详细讲解。 2.在tr中string1和string2用来指示一个字符集合范围。可以是下面的一些形式(一般要加双引号): 1) [a-d] : [a-d]表示abcd,常用的有[a-z]、[A-Z]、[0-9]等,[bfgh]表示bfgh。可以加上单或双引号 2) [C*n] : 表示字符C重复出现指定次数n。因此,[F*3]表示FFF。一般只能出现在string2中。 3) nnn : 三位八进制数,对应有效的ASCII字符。一般用于表示特定的控制字符。 速记符 a b f n r t v 4) [:class_name:] : tr支持使用内建的字符类别。常见的字符类别有: [:alnum:] 字母、数字(0-9,a-z,A-Z) [:alpha:] 字母(a-z,A-Z) [:cntrl:] 控制字符 [:digital:] [:graph:] 数字(0-9) 可打印的字符,不包含空格 含义 Ctrl-G 铃声 八进制方式 007 010 014 012 015 011 030 Ctrl-H 退格符 Ctrl-L 走行换页 Ctrl-J 新行 Ctrl-M 回车 Ctrl-X Ctrl-I tab键 [:lower:] 小写字母(a-z) [:print:] 可打印的字符,包含空格 [:punct:] 标点符号 [:space:] [:upper:] [:xdigital:] 5) 普通字符串形式: 比如 aeiou、bdfgh等。 3.选项"-c": 表示用在输入数据中出现,但是不包含在string1字符范围内的字符组成的集合,代替原来的 string1。在tr的三类操作中都可以使用选项"-c"。 eg: echo "adcfghg" | tr -cd fgca // 将显示 acfgg 输入数据中不包含在string1中的字符范围 // 是"dh",所以,实际上只是删除了字符"dh" 用于字符替换: 只需要同时给出string1和string2,可以需要不指定特别的选项。 1) Usage: tr string1 string2 空格 大写字母(A-Z) 16进制数字(0-9,a-f,A-F) 《LINUX与UNIX SHELL编程指南》读书笔记 第 31 页,共 58 页 eg: echo "adcfgh" | tr adcgw vbnle // 将显示 vbnflh (v替换a,b退回d,n替换c,l替换g...) 2) 一般string1和string2的字符个数应该相同。如果字符个数不同,分为两种情况: ① string1的字符个数少于string2的字符个数: string2种额外的字符将被忽略。 ② string1的字符个数多于string2的字符个数,又可分为两种情况: ·对于BSD系列的系统 : tr会重复string2中的最后一个字符,直到补齐到string1一样的长度。 ·对于System V的系统 : tr将截去string1中超长的部分。 GUN tr使用BSD方式,如果想使用System V方式,需要指定选项"-t"。 eg: echo "addcfghg" | tr adcgw vbn // 将打印 vbbnfnhn echo "addcfghg" | tr -t adcgw vbn // 将打印 vbbnfghg 3) tr的字符替换操作主要用途有 大小写转换等。 eg: tr [a-z] [A-Z] < // 将文件中的所有小写字母转换成大写字母 tr ":" "011" < /etc/passwd // 将passwd文件的域分隔符改为"011"即"TAB" 用于删除字符: 使用选项"-d"。 1) Usage: tr -d string1 输入数据中所有在string1中出现过的字符都将被删除。 2) echo "This is a note !"| tr -d [:space:] // 将打印 Thisisanote 即删除所有空格 tr -cd "[a-z][A-Z][n]" < // 文件中非字母或回车的字符都将被删除 用于压缩重复字符: 使用选项"-s"。压缩操作可以单独进行,也可以在替换操作或删除操作之后进行,因而 分成3种情况: 1) Usage: tr -s string1 输入数据中连续出现的字符,只有还在string1中出现过的,才会将被压缩成一个字符。 eg: echo "aaaccdefffgghhh"| tr -s adeg // 将打印 accdefffghhh (string1中无字符"cfh") tr -s "n" < // 删除文件中的空行 (即压缩回车符) 2) Usage: tr -s string1 string2 string1和string2用于替换操作,string2还用于压缩操作。 eg: tr -s "[015032]" "[012*]" 3) Usage: tr -ds string1 string2 string1用于删除操作,string2用于压缩操作。 eg: echo "aaaccdefffgghhh"| tr -ds adeg fh // 将打印 ccfh echo "aaaccdefffgghhh"| tr -d adeg // 将打印 ccfffhhh 《LINUX与UNIX SHELL编程指南》读书笔记 第 32 页,共 58 页 主要用于字符转换或者抽取控制字符。tr的大多数功能都可以用sed来完成,但有些人宁愿使用tr,因为 tr更加快捷、容易。 《LINUX与UNIX SHELL编程指南》读书笔记 第 33 页,共 58 页 第13章 登录环境 1.登录过程 1) 键入用户名和密码 2) 系统检查是否为有效用户(查询/etc/passwd文件) 3) 登录名/密码有效则系统执行环境设置文件(/etc/profile -> $HOME/.profile) 2.密码文件/etc/passwd的格式(7个域): 用户名:加密的密码:uid:gid:用户全名:用户home目录(主目录):用户的shell路径 eg: zqf:x:500:500::/home/zqf:/bin/bash 3.系统全局环境设置文件/etc/profile,此文件的设置内容一般包含有: 1) 全局或局部环境变量: 设置环境变量便于用户及其进程和应用访问它。eg:export指令等。 2) PATH信息: 设置环境变量PATH,定位包含可执行文件、库文件及一般文本文件的目录位置,便于用户快 速访问。 3) 终端设置: 使系统获知用户终端的一般特性。 4) 安全命令: 包括文件创建模式(umask)或其他安全限定。 5) 日期信息或放弃操作信息等。 4.用户个人环境变量设置文件$HOME/.profile 1) 不同的shell有不同的文件命名,bash为.bash_profile。 2) 在$HOME/.profile文件中可以通过设置相关条目以不同的值或使用uset命令来覆盖/etc/profile文件中的设 置。 1) stty用于设置终端特性。 2) Usage1: stty [option] 常用选项: -a : 以用户看的懂的格式打印当前所有的设定。 -g : 以stty的格式打印当前设定。可以用于回存stty设置。 eg:SAVEDSTTY=`stty -a` // 保存stty设置 stty $SAVEDSTTY // 还原stty的初始设置 3) Usage2: stty [-]arg // 打开[关闭]参数arg stty name value //设置特殊字符 eg: stty erase '^H' 《LINUX与UNIX SHELL编程指南》读书笔记 第 34 页,共 58 页 文件 1) 此文件保存有执行exit命令时,在进程终止前执行的命令 2) Bourne shell与其他shell不同,它没有.logout文件。Bash的logout文件名为$HOME/.bash_logout 第14章 环境和shell变量 1.四种shell变量: 1) 本地变量 2) 环境变量 还有两种变量被认为是特殊变量(只读): 3) 位置变量 4) 特定参数变量 2.本地变量 1) 在用户现在的shell生命期的脚本中使用,如果在shell中启动另一个进程或退出,此值将失效。 2) 设置变量: variable-name=value eg: name=zqf ; echo $name // 定义一个变量name,然后打印该变量,将输出 zqf 3) 显示变量: echo $variable-name 或 echo ${variable-name} 4) 清除变量: unset variable-name eg: unset name ; echo $name // 清除了变量name,echo的输出为空白 5) 显示所有本地shell变量: set 3.测试变量是否已经设置(变量置换) 1) ${var:-value} : 如果变量var未定义,返回一个默认值。 如果var存在且非空,则表达式${var:-value}的值为$var;如果var未定义,则表达式值${var:-value}为value eg: name1="zqf" ; name2=${name1:-no name} ; echo $name1 $name2 // 将打印 zqf zqf unset name1 ; name2=${name1:-no name} ; echo $name1 $name2 // 将打印 no name 2) ${var:=value} : 如果变量var未定义,设置var的默认值为value。 如果var存在且非空,则${var:=value}的值为$var;如果var为空或未定义,则var被赋值value且表达式值为 value eg: name1="zqf" ; name2=${name1:=no name} ; echo $name1 $name2 // 将打印 zqf zqf unset name1 ; name2=${name1:=no name} ; echo $name1 $name2 // 将打印 no name no name 3) ${var:?mesg} : 捕获未定义变量导致的错误。 如果var存在且非空,则${var:?value}的值为$var;如果var为空或未定义,则打印mesg并终止脚本 eg: name1="zqf" ; name2=${name1:?error,no value} ; echo $name1 $name2 // 将打印 zqf zqf 《LINUX与UNIX SHELL编程指南》读书笔记 第 35 页,共 58 页 //将打印 -bash: name1: error,no value unset name1 ; name2=${name1:?error,no value} ; echo $name1 //将打印 -bash: name1: error,no value unset name1 ; name2=${name1:?error,no value} ; echo $name2 //将打印 -bash: name1: error,no value 4) ${var:+mesg} : 测试一个变量的存在性。 如果var存在且非空,则${var:+mesg}的返回值为mesg;如果var为空或未定义,则返回null eg: name1="zqf";name2=${name1:+value ok};echo $name1 $name2 // 将打印 zqf value ok unset name1 ; name2=${name1:+value ok};echo $name1 $name2 // 将打印 null null(空行) 4.设置只读变量 : varname=value;readonly varname 查看所有只读变量 : readonly 或 readonly -p 5.环境变量 1) 登录进程称为父进程,shell中执行的用户进程均称为子进程。环境变量可用于所有子进程,这包括编辑器、 脚本和应用。环境变量最好在profile文件中定义。习惯上,所有环境变量均应该大写。 2) 设置环境变量: VARNAME=value; export VARNAME 3) 显示环境变量: echo $VARNAME 4) 查看所有的环境变量: env 5) 清除环境变量: unset VARNAME 预留的环境变量名 每一种shell有一些预留的环境变量名,这些变量名不能用作其他用途。 eg:Bourne Shell的环境变量有HOME,PATH,LANG,PWD, 命令 1) export varname 命令可以把变量varname输出到子进程中,如果在子进程中修改了变量varname的值,退 出子进程后,在子进程中被赋的值将不会传回到父进程。 2) 不可以将变量从子进程导出到父进程, 然而通过重定向就可做到这一点 8.位置参数变量 位置变量的数目有可以任意多,但一般只有$0 - $9可以被访问,多用于脚本中。 $0 $1 $2 $3 $4 $5 $6 $7 $8 $9 ($0的值为脚本名) eg: service httpd status // 对于脚本/sbin/service来说,$0的值为service,$1的值为httpd, 9.特定参数变量(7个) $# : 传递到脚本的参数的个数。 $* : 以一个单字符串显示所有向脚本传递的参数。$* 等价于"$1 $2 $3 .. $n"。 // $2的值为status。可以在service脚本中使用这些变量来传递参数值 《LINUX与UNIX SHELL编程指南》读书笔记 第 36 页,共 58 页 $! : 最后一个后台运行的进程的进程ID号。 $@ : 与$*类似,但是使用时加引号,并在引号中返回每个参数(返回一个参数列表)。$* 等价于"$1" "$2" .. "$n"。 $- : 显示shell使用的当前选项。 $? : 显示前面最后一个命令的退出状态。0表示没有错误,其他任何值表明有错误。 10.退出状态 1) $?可以在任何命令或脚本中返回此变量以获得返回信息。检验脚本退出状态时,最好将返回值赋值给一个 有意义的名字的变量,这样可以增加脚本的可读性。 2)举例: cp /usr/local/app/def >/dev/null 2>&1 cp_status=$? // 保存上一条命令(cp)的退出状态 echo $cp_status // 打印保存的状态值 第15章 引号 1.双引号(" ") 1) 使用双引号可引用除字符 $(美元符号)、`(反引号)、(反斜线) 外的任意字符或字符串。双引号不会阻止 shell对这3个字符作特殊处理(标示变量名、命令替换、反斜线转义 )。 eg: name=zqf ; echo "User name : $name" // 将打印 User name : zqf echo "The date is : `date +%d-%m-%Y`" // 将打印 The date is : 02-15-2005 echo -e "$USERt$UID" // 将打印 zqf 2.单引号(' ') 1) 如果用单引号把字符串括起来,则单引号内字符串中的任何特殊字符的特殊含义均被屏蔽。 2) 举例: echo -e '$USERt$UID' // 将打印 $USER $UID (没有屏蔽t,是因为选项"-e"的缘故) echo '$USERt$UID' // 将打印 $USERt$UID 3.反引号(` `) 1) shell将反引号中的内容作为一个系统命令,并执行其内容。使用这种方法可以替换输出为一个变量。 2) 举例: a=`date +%d-%m-%Y` ; echo $a // 将打印 16-02-2005 4.反斜线() 1) 如果下一个字符有特殊含义,反斜线防止shell误解其含义,即屏蔽其特殊含义。 2) 下述字符包含有特殊意义: & * + ^ $ ` " | ? 3) 在打印字符串时要加入八进制字符(ASCII相应字符)时,必须在前面加反斜线,否则shell作普通数字处 理。 500 2) 如果要查询包含空格的字符串,经常会用到双引号。 《LINUX与UNIX SHELL编程指南》读书笔记 第 37 页,共 58 页 《LINUX与UNIX SHELL编程指南》读书笔记 第 38 页,共 58 页 第16章 shell脚本介绍 1.脚本内容 shell脚本不是复杂的程序,它是按行解释的。 1) shell脚本第一行总是以#!/bin/sh开始,这段脚本通知shell使用系统上的Bourne shell解释器。 2) shell脚本加注释行要求该行的第一个字符为#,第二行注释中写入脚本名是一个好习惯。 3) shell脚本从上到下执行。运行脚本前需要增加其执行权限。确保正确建立脚本路径。 第17章 条件测试 命令 1) test命令用于测试字符串,文件状态和数字。test一般有两种格式,即: test condition 或 [ condition ] (使用方括号时,要注意在条件两边加上空格) 2) test命令的退出状态: 0表示成功,其他非0为失败 2.测试文件状态 1) 常见的文件状态测试: -b filename -c filename : 当filename存在并且是块文件时返回真(返回0) : 当filename存在并且是字符文件时返回真 -d pathname : 当pathname存在并且是一个目录时返回真 -e pathname : 当由pathname指定的文件或目录存在时返回真 -f filename -h filename -p filename -s filename -S filename -t fd : 当filename存在并且是正规文件时返回真 : 当filename存在并且是符号链接文件时返回真 (或 -L filename) : 当filename存在并且是命名管道时返回真 : 当filename存在并且文件大小大于0时返回真 : 当filename存在并且是socket时返回真 : 当fd是与终端设备相关联的文件描述符时返回真 -g pathname : 当由pathname指定的文件或目录存在并且设置了SGID位时返回真 -k pathname : 当由pathname指定的文件或目录存在并且设置了"粘滞"位时返回真 -r pathname : 当由pathname指定的文件或目录存在并且可读时返回真 -u pathname : 当由pathname指定的文件或目录存在并且设置了SUID位时返回真 -w pathname : 当由pathname指定的文件或目录存在并且可写时返回真 -x pathname : 当由pathname指定的文件或目录存在并且可执行时返回真 -O pathname : 当由pathname存在并且被当前进程的有效用户id的用户拥有时返回真(字母O大写) -G pathname : 当由pathname存在并且属于当前进程的有效用户id的用户的用户组时返回真 file1 -nt file2 : file1比file2新时返回真 file1 -ot file2 : file1比file2旧时返回真 《LINUX与UNIX SHELL编程指南》读书笔记 第 39 页,共 58 页 test -c /dev/hda ; echo $? // 将打印 1 表示test命令的返回值为1,/dev/hda不是字符设备 [ -w /etc/passwd ]; echo $? // 查看对当前用户而言,passwd文件是否可写 3.测试时使用逻辑操作符(逻辑与、或、非) 用于[ ]操作符 1) -a 逻辑与,操作符两边均为真,结果为真,否则为假。 2) -o 逻辑或,操作符两边一边为真,结果为真,否则为假。 3) ! 逻辑否,条件为假,结果为真。 4) 举例: [ -w -a -w ] ;echo $? // 测试两个文件是否均可写 4.字符串测试 字符串测试是错误捕获很重要的一部分,特别在测试用户输入或比较变量时尤为重要 1) 常见字符串测试 -z string -n string str1 = str2 str1 != str2 : 字符串string为空串(长度为0)时返回真 : 字符串string为非空串时返回真 : 字符串str1和字符串str2相等时返回真 : 字符串str1和字符串str2不相等时返回真 str1 < str2 : 按字典顺序排序,字符串str1在字符串str2之前 str1 > str2 : 按字典顺序排序,字符串str1在字符串str2之后 2) 举例: name="zqf"; [ $name = "zqf" ];echo $? // 打印 0 表示变量name的值和字符串"zqf"相等 5.测试数值(比较整数) 1) 常见数值测试 int1 -eq int2 : 如果int1等于int2,则返回真 int1 -ne int2 : 如果int1不等于int2,则返回真 int1 -lt int2 int1 -le int2 int1 -gt int2 : 如果int1小于int2,则返回真 : 如果int1小于等于int2,则返回真 : 如果int1大于int2,则返回真 int1 -ge int2 : 如果int1大于等于int2,则返回真 2) 举例: x=1 ; [ $x -eq 1 ] ; echo $? // 将打印 0 表示变量x的值等于数字1 x=a ; [ $x -eq "1" ] // shell打印错误信息 [: a: integer expression expected 用于数值和字符串运算 1) expr Usage: expr expression 2) expr命令运算完毕后,除了会返回表达式运算的结果外,还会生成一个expr执行状态码表示expr的执行 状态。 3) expr的执行状态码: 0 : 表达式结果不是0或null 1 : 表达式结果是0或null 2 : 表达式无效 《LINUX与UNIX SHELL编程指南》读书笔记 第 40 页,共 58 页 echo $? // 输出结果为1 (expr的执行状态码) 4) expression: 可以是一个数值表达式,也可以是一个字符串表达式。可以进行数值或字符串运算。 eg: expr zqf // 将打印 zqf 支持的运算符 0) expr的expression中,运算符前后都要留一个空格,并且一般最好加上单引号。 1) expr的expression中可使用加(+)减(-)乘(*)整除(/)取余(%)运算符。 2) expr的expression中还可以使用两类运算符: ① | : 如果第一个参数不是null也不是0,则使用第一个参数为算子,否则使用第二个参数为算子。 & : 如果第一个参数不是null也不是0,则使用第一个参数为算子,否则使用数值0为算子。 eg: a=0 ; expr $a '|' 4 + 5 // 将打印 9 a=6 ; expr '(' $a '&' 4 ')' + 5 // 将打印 11 a=0 ; expr '(' $a '&' 4 ')' + 5 // 将打印 5 ② 比较运算符: <、<=、=、==、!=、>=、> ( == 相当于 = ) 比较两个参数的逻辑关系,如果逻辑关系正确,返回数值1,否则返回数值0。如果两个参数都是数字则按 算术大小比较,否则按字典顺序比较。 eg: b=beijing ; expr $b = beijing // 将打印 1 b="c" ; expr $b '<' d // 将打印 1 用于整数运算 1) expr的expression中运算数只能是整数不能是小数。 2) 举例: expr '(' 2 '+' 3 ')' '*' 2 // 将打印 10 LOOP=0 ; LOOP=`expr $LOOP + 1` // 在循环结构中,expr可用于增量计数 可以用来测试一个数,如果试图计算非整数,expr将返回错误信息。 eg: r=4 ; expr $r + 4 // 将打印 8 r="a" ; expr $r + 4 // 将打印错误信息 expr: non-numeric argument expr 1.5 + 4 // 将打印错误信息 expr: non-numeric argument 用于字符串运算 1) 常见字符串运算符: expr length STRING : 返回字符串STRING的长度 expr index STRING CHAR : 返回字符CHAR在字符串STRING中第一次出现是的位置(没有出现则返回0) expr substr STRING POS LEN : 返回STRING的子字符串(从位置POS开始长度为LEN) eg: expr length "Linux and Unix Shell Programming" // 返回字符串的长度,即打印 22 expr index "Linux and Unix Shell Programming" i // 将打印 2 expr substr "Linux and Unix Shell Programming" 16 7 // 将打印 Shell P 《LINUX与UNIX SHELL编程指南》读书笔记 第 41 页,共 58 页 ① expr match STR REGEXP : STR是字符串,REGEXP是正则表达式。返回STR中匹配REGEXP的字符 个数。 expr STR:REGEXP : 相当于 expr match STR REGEXP。 eg: expr : b // 将打印 0 expr : acc // 将打印 3 expr 1234dfgh : '[0-9]*' // 将打印 4 expr 1234dfgh : '.*' // 将打印 8 ② 在REGEXP中使用小括号(要加上转义符""),则expr返回的是由这对括号所包括的内容。 eg: expr abcdefgh : '...(...)..' // 将打印 def expr : '(.*).doc' // 将打印 accounts 第18章 控制流结构 1.退出状态 1) 四种退出状态: ① 最后命令退出状态(用"$?"指示) ② 控制次序命令"$$"和"||" ③ shell(脚本)退出状态 ④ 函数返回码 2) exit [n] :退出并返回退出码n,n为整数 ① 在shell命令行下使用 exit [n],将退出当前shell ② 在shell脚本中使用 exit ,将退出脚本shell并返回exit上一条命令的退出状态码。 ③ 在shell脚本中使用 exit n,将退出脚本shell并返回退出状态码n 2.控制结构 1) 流控制 : if-then-else语句、case语句 2) 循环 : for循环、until循环、while循环语句 -then-else语句 1) 语法结构: if condition1 then // 如果condition1为真(返回值为0),condition一般是条件测试表达式 // 那么 // 执行语句块1 // 如果(条件1不成立)而条件2成立 (If语句可以有许多elif部分) // 那么 // 执行语句块2 statements1 [elif condition2 then statements2] 《LINUX与UNIX SHELL编程指南》读书笔记 第 42 页,共 58 页 statements3 ] fi // 执行语句块3 // 完成 (if语句必须以单词fi终止。在if语句中漏写fi是最一般的错误) 2) if语句的各个condition和statements部分不能留空。如果想留空的话,必须使用shell提供的空命令":"(即 冒号),来占据要留空的位置。空命令表示永远为真。 3) 条件condition可以是命令语句列表,以最后一个命令的退出状态用作条件值。 语句 1) case语句为多选择语句。一个值与多个模式匹配,如果匹配成功,执行相匹配的命令。 2) 语法结构: case expression in pattern1 ) pattern2 ) ...... patternN ) esac 3) 表达式按顺序匹配每个模式。一旦有一个模式匹配成功,则执行完该模式相应命令后退出不再继续匹配。 4) 模式部分可以包括元字符: * 任意字符、? 任意单字符、[ ] 类或范围中任意字符。 5) 为了防止表达式未匹配到任何模式,可以在最后一个模式中使用星号*来表示匹配任意表达式expression 6) 每个模式的语句块必须以2个分号(;;)结尾 7) 在模式pattern中可以使用或操作符"|"。 eg: vt100 | vt102 | vt 220 ) statements ;; 循环 1) 语法结构: for name [in list] do done 2) list应该是一系列由空格分隔的字符序列(单词),省略in list时默认为$@ (命令行的参数列表) 3) 列表list可以是命令替换、变量名替换、字符串和文件名列表(*可表示当前目录下所有文件) 4) for循环执行的次数取决于列表list中单词的个数 5) 在for循环体中一般应该要出现变量$name,但也可以不出现。 // 每一次循环,依次把列表list中的一个值赋予变量name // 循环体开始标志 // 变量name每取一次值时,循环体执行一遍 // for循环体结束标志 statements1 ;; statements2 ;; // expression为一表达式 ( in不能忘掉了 ) // 如果表达式expression匹配模式pattern1 // 则执行语句块1,然后退出。如果不匹配,则进行模式2的匹配 // 如果表达式expression匹配模式pattern2 // 则执行语句块2,然后退出。如果不匹配,则进行模式3的匹配 // ...... // 如果表达式expression匹配模式patternN // 则执行语句块N,然后退出。 // case语句结束标志 statementsN ;; statements using $name 《LINUX与UNIX SHELL编程指南》读书笔记 第 43 页,共 58 页 循环 1) 当条件为假时执行循环体(执行循环体直到条件为真时停止) 2) 语法结构: until condition // 当条件condition不成立时 do done 3) until释义: until prep. 在...以前,到...为止 ; conj. 在...以前, 到...为止, 直到...才 4) until在每次循环开始前先检查条件condition,不同于C语言的"直到.."(先循环后检查条件)结构 5) condition一般是test一类的表达式。也可是命令语句列表,则以最后一个命令的退出状态作条件值。 循环 1) 当condition为真时执行循环体命令 2) 语法结构: while condition do done 3) while释义: while conj.当...的时候 4) condition一般是test一类的表达式。也可是命令语句列表,则以最后一个命令的退出状态作条件值。 5) while循环常用于从一个文件中一次循环读取一行数据,这时需要使用输入重定向。 eg:while read LINE ; do echo $LINE ; done < 6) 在5)的情况下,while也可以一次把一行数据的各个域分别读入到不同的变量中。(注意设定IFS变量) eg: IFS=: ; while read F1 F2 F3 ; do echo -e "$F1t $F2t $F3t" ; done < 7) 如果希望每次处理2个记录,则可在while后放一个read var1语句,再在循环体中放一个read var2语句 语句 1) break语句允许退出循环或case语句。 2) Usage: break [n] // 跳出[n层]循环 ue 1) continue语句用于跳出当前本轮循环步,重新开始新一轮的循环步。 2) Usage: continue statements // 执行condition。(condition可以是cmd或test一类表达式) // 如果cmd的退出状态为0,则执行循环体。cmd退出状态不为0,退出循环。 // 循环体 // 循环体结束,返回第一步。 // 开始执行 // 循环体 // do循环结束标志 statements 第19章 shell函数 《LINUX与UNIX SHELL编程指南》读书笔记 第 44 页,共 58 页 1.函数 1) 定义函数的语法: 函数名 () { } 2) 可以在命令行或脚本中定义函数。所有函数必须先定义后使用,在脚本中函数一般在开始部分定义。 3) 调用函数仅使用其函数名即可,可以带参数。函数一旦定义了,可作为一个合法的命令,用在所有的后继 shell中。 eg: funcname arg1 arg2 ... 4) 在一个脚本中定义的函数只能用在那个脚本和所有由该脚本生成的子shell中。 5) 向函数传递参数就像在一般脚本中使用特殊变量$1、 $2 . . . $9和 $@ 一样。 6) 可以在一个函数的定义内部调用另一个函数 -- 函数链接。 7) 可以再一个函数的定义内部调用这个函数本身 -- 函数递归。 2.从调用函数中返回,可以有两种处理方式: 1) 让函数正常执行到函数末尾,然后返回脚本中调用函数的控制部分(默认方式)。 2) 使用return返回脚本中函数调用的下一条语句,可以带返回值。0为成功,非0为有错误。 3.在shell中使用函数 1) 将函数的定义写入函数文件func_file中。 2) 将函数文件func_file的内容载入shell,在bash下使用命令: source func_file 3) 当需要修改函数定义时,先删除函数( unset func_name ),然后再修改文件中有关函数func_name的内 容。 4) 重新载入函数文件( source func_file ),使函数修改生效。 问题 echo语句的使用类型依赖于使用的系统是LINUX、BSD还是System V 1) 使提示符放在语句末尾,而不是在新行的行首 BSD/Linux : System V : 2) LINUX的echo语句必须额外使用-e选项用来显示反馈控制字符。 echo -n "string" echo "stringc" or function 函数名 () { } statements // 小括号"()"不能掉 // "{" 和statements之间至少要有一个空格 statements 第20章 向脚本传递参数 《LINUX与UNIX SHELL编程指南》读书笔记 第 45 页,共 58 页 1) 选项部分最多可包含12个不同的值,如果必须控制不同的命令选项,就要加入大量脚本。 2) shell提供shift命令以帮助偏移选项,使用shift可以去除只使用$1到$ 9传递参数的限制。 命令 1) 功能: 它每次将参数位置向左偏移一位 2) shift Usage: shift N // N为一个数字 3) 举例: shift `expr $# - 1` // 使命令行的最后一个参数(通常为文件名)成为$1 // 也可以用eval命令来实现上述功能: eval echo $$# (显示命令行最后的参数) 4)注意: 当脚本中使用了一次shift后,相应脚本命令行的 $# 值会减少1, $* 和$@ 的值也相应的变化 s 1) getopts可以编写脚本,使控制多个命令行参数更加容易。getopts用于形成命令行处理标准形式。 2) getopts Usage: getopts option_string variable_name 3) getopts命令中的option_string字符串: ① getopts读取字符串option_string,获知脚本可以使用的有效选项(在命令行中选项应该以"-"开头)。 ② option_string由字母和冒号组成,每一个字母就是一个有效选项。 如果option_string中一个字母后跟一个":",表示该字母选项后应该有一个参数。 如果option_string以":"开头,表示当命令行中出现了无效选项时,getopts不打印错误信息。 eg: getopts :ac:h optchar // 表示脚本文件在命令行下只可以接受选项-a -h -c(必须带参数) s的运行方式 1) getopts语句一般和while循环、case结构联合使用。 eg: while getopts :ac:h OPT do case $OPT in a) statements ;; // 当出现选项-a时,要执行的语句 c) statements ;; // 因为选项-c要带参数,该参数由环境变量$OPTARG指示 h) statements ;; // 当出现选项-h时,要执行的语句 esac done 2) getopts语句放在while循环结构中,getopts语句每执行一次就依次从option_string(如上例的:ac:h)中取出 一个字母(忽略":"),如果在命令行中有选项匹配该字母,则变量variable_name(如上例的OPT)将被赋值为该 选项字母,如果该选项带有一个参数(字母后带冒号的情形下),该选项的参数将被保存到环境变量$OPTARG 中。 3) 每次getopts执行时,如果在命令行的第x()个参数中匹配到字母选项,则环境变量OPTIND的值为 x+1。在命令行脚本启动时,OPTIND 会被初始化为1。 《LINUX与UNIX SHELL编程指南》读书笔记 第 46 页,共 58 页 s对错误的处理 1) 两类错误: ① 命令行中出现非法选项字母(没有被包含在option_string中的)。 ② 需要带参数的选项在命令行中没有给出参数(参数应该跟在该选项字母后)。 2) 错误处理方式: ① silent方式 : option_string以冒号开头,即getopts将不打印错误信息。 ② 非silent方式 : getopts将打印错误信息。 当设置环境变量OPTERR为 0 时,即使在非silent方式下getopts也不会打印错误信息。 3) 错误处理: ① 当getopt遇到非法选项时,变量variable_name将设置为"?"。 ·在非silent方式下,变量OPTARG被清零,然后getopts打印错误信息。 ·在silent方式下,该非法选项字母将放入变量OPTARG,getopts不打印错误信息。 ② 当需要带参数的选项在命令行中没有给出参数时,变量variable_name将赋值"?"。 ·在非silent方式下,变量OPTARG被清零,然后getopts打印错误信息。 ·在silent方式下,该非法选项字母将放入变量OPTARG,getopts不打印错误信息。 ③ 可以看出,getopts对两类错误并未作区分,采用了同样的处理。 /Linux命令行程序常用的选项字母 -a -c -d -e -f -h -i -l -o -q -p -v 扩展 计数、拷贝 目录、设备 执行 文件名、强制 帮助 忽略状态 注册文件 完整输出t 退出、安静模式 路径 详细显示、版本 第21章 创建屏幕输出 《LINUX与UNIX SHELL编程指南》读书笔记 第 47 页,共 58 页 2) tput Usage: tput [-V] [-S] [-Ttermtype] capname ① 选项-V: 显示程序所用的ncurses版本; 选项-S: 从标准输入获取capname参数。(eg: tput -S << MAYDAY) ② 选项-T termtype : 省略此参数时,tput从环境变量TERM中获取termtype值(T与termtype间可无空格) ③ tput [-T termtype] init // 在使用tput前,需要在脚本或命令行中使用此命令初始化终端 ④ tput [-T termtype] reset 3) tput产生三种不同的输出:字符型、数字型和布尔型(真/假)。即: capname参数 ① 大部分常用字符串: bel 警铃 粗体 blink 闪烁模式 bold clear 清屏 cnorm cup x y el ell 不隐藏光标 移动光标到屏幕位置(x,y) 清除到行尾 清除到行首 civis 隐藏光标 // 将环境变量TERM复位(reset)为termtype给定的值 ⑤ tput [-T termtype] longname // 打印终端类型termtype的正式长格式名称 smso 启动突出模式 rmso 停止突出模式 smul 开始下划线模式 rmul 结束下划线模式 sc rc 保存当前光标位置 恢复光标到最后保存位置 逆转视图 sgr0 正常屏幕 rev cols 列数目 it tab设置宽度 lines 屏幕行数 ③ 两种布尔操作符: chts 光标不可见 hs 具有状态行 // 清屏 // 定位光标到行23列4 4) 举例: tput clear tput cup 23 4 tput bel 2.使用转义序列和产生控制码 // 响铃 ② 大部分常用数字输出: 《LINUX与UNIX SHELL编程指南》读书笔记 第 48 页,共 58 页 2) 解析: echo -e "003[?25l" // 发送一转义序列以关闭光标使之不可见。003 为转义键取值 // 表示接下来是一个控制字符的序列;[ 为分隔符 // ?25l 为控制字符的实际序列 3) 控制序列一般嵌在echo语句中,可用的语法有: ① Linux/BSD : echo -e "033[<控制字符实际序列>" ② System V : echo "033[<控制字符实际序列>" ③ Generic : echo " 4) 常用的 <控制字符实际序列> 关闭光标 打开光标 清屏 3.使用颜色控制码 1)屏幕颜色控制代码: <背景色代码;前景色代码m> eg: echo -e "033[40;32m" 2) 常用前景色代码: 4.创建精致菜单(按单键选择菜单),shell编程使用的主要结构 #!/bin/sh 30 黑色 34 蓝色 31 红色 35 紫色 32 绿色 36 青色 33 黄(或棕)色 37 白(或灰)色 40 黑色 44 青色 41 红色 45 蓝色 42 绿色 46 青色 43 黄(或棕)色 47 白(或灰)色 // 产生一个黑色背景加绿色前景色 ?25l(是字母l) ?25h 2J 3) 常用背景色代码: 《LINUX与UNIX SHELL编程指南》读书笔记 第 49 页,共 58 页 get_char() { # get_char # save current stty settings SAVEDSTTY=`stty -g` stty cbreak dd if=/dev/tty bs=1 count=1 2> /dev/null stty -cbreak # restore stty stty $SAVEDSTTY } echo -e -n "tYour Choice [1,2,3,4,5] :" read CHOICE CHOICE=`get_char` case $CHOICE in 1) doing submenu1's things ;; 2) doing submenu2's things ;; 3) doing submenu3's things ;; 4) doing submenu4's things ;; 5) doing submenu5's things ;; *) default ;; 第22章 创建屏幕输入 1.屏幕输入或数据输入是接受输入(这里指键盘)并验证其有效的能力。如果有效,接受它,如果无效,放弃 该输入。 2.本章主要给出了几个shell脚本例子,没有提到特别的知识点。 第23章 调试shell脚本 《LINUX与UNIX SHELL编程指南》读书笔记 第 50 页,共 58 页 脚本的一般错误 1) 循环错误: for、while、until和case语句中的错误是指实际语句段不正确。也许漏写了固定结构中的一个保 留字。 2) 典型的漏写引号: 解决这类错误的唯一方案是在脚本中确保所有引号成对出现。使用vi的set nu选项调试错 误,可以定位文本行号。 3) 测试语句错误: 使用 -eq 语句时忘记在测试条件一边使用数字取值;在变量和方括号间忘记加空格;在方括号 里漏写操作符。 4) 字符大小写: 经验上讲大多数错误是由于使用变量时大小写保持不一致。 5) for循环: 使用for循环时,有时会忘了在循环的列表部分用$符号,特别是在读取字符串时。 3.调试脚本工具 1) echo 最有用的调试脚本工具是echo命令。一般在可能出现问题的脚本重要部分加入echo命令,例如在变量读取 或修改操作其前后加入echo命令。使用最后状态命令判断命令是否成功,这里需要注意的是,不要使用echo 命令后直接加最后状态命令,因为此命令永远为真。 2) set ① set命令常用的调试选项: set -n 读命令但并不执行。 set -v 显示读取的所有行。 set -x 显示所有命令及其参数。 将set选项关闭,只需用+替代-。 ② 可以在脚本开始时将set选项打开,然后在结束时关闭它。或在认为有问题的特殊语句段前后打开及关闭 它。 4.跟踪错误的最好方式是亲自查阅脚本,并使用set命令并加大量的echo语句。 第24章 shell嵌入命令 嵌入命令 这些命令是在实际的Bourne shell里创建而不是存在于/bin或/usr/bin目录里。嵌入命令比系统里的相同命令 要快。(类似于dos的内部命令和外部命令之分) shell嵌入命令完整列表 : 空,永远返回为true 《LINUX与UNIX SHELL编程指南》读书笔记 第 51 页,共 58 页 break 退出for、while、until或case语句 cd echo eval exec exit pwd read 改变到当前目录 执行循环的下一步 反馈信息到标准输出 读取参数,执行结果命令 执行命令,但不在当前shell 退出当前shell 显示当前目录 从标准输入读取一行文本 使变量只读 continue export 导出变量,使当前shell可利用它 readonly set shift test trap return 退出函数并带有返回值 控制各种参数到标准输出的显示 命令行参数向左偏移一个 评估条件表达式 当捕获信号时运行指定命令 times 显示shell运行过程的用户和系统时间 ulimit 显示或设置shell资源 umask 显示或设置缺省文件创建模式 unset 从shell内存中删除变量或函数 wait 3.一些shell嵌入命令 1) pwd : 显示当前目录。 2) set : 在查看调试脚本、打开或关闭shell选项时,曾用到set命令。 set也可用于在脚本内部给出其运行参数,在脚本中使用 set param1 param2 ... 且在命令行下不向该脚本传递 参数时,系统会将param1、param2..当作$1、$2..来看待。当测试一段脚本且脚本包含参数时,这样使用set 命令有很多用处。其一就是不必在每次运行脚本时重复输入参数。 3) times : times命令给出用户脚本或任何系统命令的运行时间。第一行给出shell消耗时间,第二行给出运行 命令消耗的时间。 4) type : 使用type查询命令是否仍驻留系统及命令类型。type打印命令名是否有效及其路径位置。 5) ulimit : ulimit设置运行在shell上的显示限制。通常此命令出现在文件/etc/profile中。也可以从当前shell或 用户的.profile文件中将之移入用户需要的位置。 ① ulimit一般格式: ulimit options ② 一些常用的选项: -a -c 显示当前限制 限制内核垃圾大小 等待直到子进程运行完毕,报告终止 《LINUX与UNIX SHELL编程指南》读书笔记 第 52 页,共 58 页 6) wait : wait命令等待直到一个用户子进程完成,可以在wait命令中指定进程ID号。如果并未指定,则等待 直到所有子进程完成。 《LINUX与UNIX SHELL编程指南》读书笔记 第 53 页,共 58 页 第25章 深入讨论<< 1. << 的用法 1) 该命令的一般形式为: command < 2) 分界符word可以是你所定义的任何字符串。如果在text中使用tab键,可以在"<<"之后加一个横杠"-" 3) 可以使用"<<"来创建文件、显示文件列表、排序文件列表以及创建屏幕输入等。 2. << 应用举例 1) 快速创建一个文件: cat >> myfile < 现在可以输入一些文本,结束时只要在新的一行键入ENDFILE即可,这样就创建了一个名为myfile的文 件,该文件中包含了一些文本。 2) 快速创建打印文档: lpr < 现在可以输入一些文本,结束时只要在新的一行键入ENDFILE即可,这样输入的文本就可以被lpr打印了。 3) "<<"的用途很广,特别是在连接某些应用程序如使用ftp时。你可以灵活地使用"<<"来自动运行以前编写的 脚本,从而完成各种不同的任务。 4) 一个自动ftp传输脚本示例: 当要定期登陆ftp下载文件时,编写脚本很有用。 #!/bin/sh ftp -i -n 172.25.151.123 < user anonymous zqf@ // 匿名登陆 binary cd /pub/data quit // 设置ftp的传输模式为binary // 在ftp服务器上切换目录 // 退出ftp程序 word // 当shell看到"<<"时,它就会知道下一个词是一个分界符 // 在该分界符以后的内容都被当作输入 // 直到shell又看到该分界符(位于单独的一行) get ~zqf/ // 下载文件 FTPEND 第26章 shell工具 1.创建保存信息的文件 1) 任何脚本都应该能够创建临时文件或日志文件。在运行脚本做备份时,最好是保存一个日志文件。 《LINUX与UNIX SHELL编程指南》读书笔记 第 54 页,共 58 页 3) 在创建日志文件或临时文件时,最好能够使它的文件名具有唯一性。 2.使日志文件的文件名具有唯一性: 文件名中加入日期和时间信息 1) date命令用法: ① Usage: date [option] + ② 常用 +%d%m%y +%R +%T +%a +%A +%b +%B +%D +%r +%x 2) 在文件名中含有日期的一个简单办法就是使用置换。把含有日期格式的变量附加在相应的日志文件名后面即 可。 eg: 脚本代码示例: MYDATE=`date +%d%m%y` LOGFILE=/tmp/backup_log.$MYDATE # create the file >$LOGFILE 3.使临时文件的文件名具有唯一性: 使用环境变量$$ 环境变量$$中保存有你所运行的当前进程的进程号。因为脚本在运行时的进程号是唯一的,如果运行的脚本 中需要创建一个临时文件,我们只要创建一个文件并在后面附加上$$即可保证临时文件的文件名具有唯一性 (类上)。 4.信号 1) 信号:信号就是系统向脚本或命令发出的消息,告知它们某个事件的发生。信号可以用数字代表。 2) 最常用的信号及它们的含义: signum 1 2 sigspec SIGHUP SIGINT meanings 挂起或父进程被杀死 来自键盘的中断信号,通常是 16:34 16:34:50 Mon Monday Jan January 01/03/05 04:41:28 PM 01/03/2005 030105 +%d-%m-%Y 03-01-2005 ③ 举例: date +%d/%m/%Y" "%R // 打印 19/02/2005 21:12 《LINUX与UNIX SHELL编程指南》读书笔记 第 55 页,共 58 页 9 11 15 SIGKILL SIGSEGV SIGTERM 无条件终止 段(内存)冲突 软件终止(缺省杀进程信号) 3) 列出系统所有的信号: kill -l 4) 杀死一个进程: 或 trap -l kill [-s sigspec | -n signum | -sigspec] 用kill发送信号1将使一个进程重新读入配置文件,kill缺省发送信号15。 eg: kill -1 httpd // 使httpd进程从新读取配置文件 5.信号捕获 1) 有些信号可以被应用程序或脚本捕获,并依据该信号采取相应的行动。另外一些信号不能被捕获。 2) 在编写shell脚本时,一般只需关心信号1、2、3和15。 3) 当脚本捕捉到一个信号后,它可能会采取下面三种操作之一: ① 不采取任何行动,由系统来进行处理。 ② 捕获该信号,但忽略它。 ③ 捕获该信号,并采取相应的行动。 第一种处理方式是默认方式,如果想要采取另外两种处理方法,必须使用trap命令。 在脚本中捕捉信号 1) trap Usage: trap [arg] [signal_spec ...] ① arg是捕捉到信号以后所采取的一系列操作,可以是一个函数或命令行,arg要用双引号引起来,也可以用单 引号。 ② signal_spec ... 是信号列表(空格分割),可以是signum或sigspec 2) 一些最常见的trap命令用法: trap "" 2 3 trap 2 3 3) 举例1: trap "echo the terminal stays locked" 2 3 15 trap命令捕捉信号2、3和15。如果一个用户试图中断该脚本的运行,将会得到一个不成功的提示。 举例2: trap "" 1 2 3 15 和 trap 1 2 3 15 在编写脚本时,如果希望在脚本运行的某些关键时刻脚本运行不被中断,通过设置trap来屏蔽某些信号就可 以解决这个问题。在这些关键性的处理过程结束后,再重新打开信号。 4) 当脚本捕获到信号时,通过使用trap命令,可以更好地控制脚本的运行。捕获信号并进行处理是一个脚本 健壮性的标志。 // 忽略信号2和信号3,用户不能终止该脚本 // 复位信号2和3,用户可以终止该脚本 trap "commands" 2 3 // 如果捕捉到信号2或3,就执行相应的commands命令 《LINUX与UNIX SHELL编程指南》读书笔记 第 56 页,共 58 页 1) eval命令将会首先扫描命令行进行所有的变量置换,然后再执行该命令。该命令适用于那些一次扫描无法 实现其功能的变量。该命令对变量进行两次扫描。 2) 举例: cmdline="cat /etc/password" ; eval $cmdline // 显示结果与 cat /etc/password 等效。 1) 当希望在系统全局的日志文件messages(/var/log或/var/adm目录下)中记录信息的时候,logger命令是一 个非常好的工具。 2) 用户可能会出于下列的原因向该全局日志文件messages中发送消息: ① 在某一个特定的时间段出现的访问或登录。 ② 你的某些执行关键任务的脚本运行失败。 ③ 监控脚本的报告。 3) logger Usage: logger [ -p pri ] [ -i ] message ① -p pri 指定消息message的优先级,缺省值为提示用户注意的优先级。 ② -i 在每个消息中记录发送消息的进程号。 欲发送的消息字符串,使用双引号,其中可以使用变量替换。 ③ message 4) 向日志文件中发送信息的一个更为合理的用途就是用于脚本非正常退出时。如果希望向日志文件中发送消 息,只要在捕获信号的退出函数中包含logger命令即可。 eg: logger -p notice "This is a test message" // 此语句将附加到文件/var/log/messages尾 第27章 几个脚本例子 1.在对系统进行某些更新时,你可能不希望用户登录,这时可以使用/etc/nologin文件,大多数系统都提供这 个文件。一旦在/etc目录中使用touch命令创建了一个名为nologin的文件,除root以外的任何用户都将无法 登录。记住,该文件要对所有用户可读。当决定恢复用户登录时,只要删除该文件即可。 第28章 运行级别脚本 1.运行级别脚本 1) 如果希望在系统启动时自动运行某些应用程序、服务或脚本,或者在系统关机时能够正确地关闭这些程序, 那么需要创建运行级别脚本。外,绝大多数LINUX发行版都含有这种基于System V 的运行级别配置目录。 2) 如果需要在某一个特定的运行级别启动或停止程序,就得创建运行级别脚本(它们通常被称为rc脚本) 《LINUX与UNIX SHELL编程指南》读书笔记 第 57 页,共 58 页 4) 运行级别配置目录的机制使得rc脚本只在系统切换运行级别时有效。它不负责检查某一运行级别中所有的 特定服务是否都已经被启动或停止。这是shell编程者的事。 2.运行级别目录 1) Linux的运行级别目录: 3) 运行级别目录中含有一系列启动服务的脚本。这里的“服务”可以是守护进程、应用程序、服务器、子系统或 脚本进程。 b脚本 1) 在系统启动的过程中,将会启动一个名为init的进程(它是系统中所有进程的祖先)。它所要完成的一部分工 作就是看看需要启动哪些服务,应当缺省地进入哪一个运行级别。它通过查看配置文件/etc/inittab来获得上述 信息的。init进程还按照该文件中的设置加载特定的进程。 2) inittab文件所包含的域具有严格的格式。该文件中每个条目的格式为: id:rstart:action:process ① id域是相应进程的唯一标识。rstart域所包含的数字表示运行该进程的级别。 ② action域告诉init进程如何对待process所对应的进程。这里可以有很多种动作,但是最常见的是wait和 respawn。wait意味着当进程启动后等待它结束。respawn则意味着如果该进程不存在,则启动相应的进程, 如果它存在,那么只要它一掉下来就立即重新启动它。 ③ process域包含了实际要运行的命令 3) inittab脚本的行内容举例: l3:3:wait:/etc/rc.d/rc 3 1:2345:respawn:/sbin/mingetty tty1 x:5:respawn:/etc/X11/prefdm -nodaemon 4.运行级别 1) init进程在系统完全就绪之前所做的最后几项工作之一就是执行缺省运行级别所包含的所有脚本。该进程是 通过/etc /rc.d/rc(或/etc/)来启动这些脚本的。它的作用是首先杀死该运行级别所包含的进程再启动这些进 程。 2) rc脚本将会使用for循环来依次查看相应运行级别目录中的文件,给每一个链接名以K开头的相应脚本赋予 参数stop; 给每一个链接名以S开头的相应脚本赋予参数start。在运行级别切换时,rc脚本也会完成同样的 工作,只不过根据相应的运行级别来启动或停止对应的脚本。 /etc/rc.d 和 /etc/rc.d/rcX.d (X=0-6) 2) 确定Linux当前的运行级别: runlevel 《LINUX与UNIX SHELL编程指南》读书笔记 第 58 页,共 58 页 4) 一般来说,rc脚本都应当能够接受参数 start 和 stop。可选的参数包括 restart 和 status。 5) 各种运行级别(run level) 运行级别0 : 启动和停止整个系统 运行级别1 : 单用户或管理模式 运行级别2 : 多用户模式;部分网络服务被启动。有些系统将其作为正常运行模式,而不是级别3 运行级别3 : 正常操作运行模式,启动所有的网络服务 运行级别4 : 用户定义的模式,可以使用该级别来定制所需要运行的服务 运行级别5 : 有些UNIX系统变体将其作为缺省X-windows模式,还有些系统把它作为系统维护模式 运行级别6 : 重启动 6) 运行级别脚本名(链接)的格式 脚本名的格式: SnnScript_name 或 KnnScript_name ① 链接脚本名实际是在rc脚本的名称前加上Snn 或 Knn。 ② S 代表启动相应的进程,K 代表杀死相应的进程。 ③ nn: 是00到99的两位数字,同一个rc脚本在不同的rcX.d目录中的链接名应采用相同的数字。 ④ 当init进程调用相应的运行级别脚本时,杀进程按照从高到低的K序号进行。而启动进程按照从低到高的 序号进行。如果使用的是LINUX系统,K序号将按照从高到低的顺序执行。 5.安装自己的运行级别脚本的步骤 1) 编写该rc脚本,确保它符合调用标准(脚本要接受start和stop参数)。 2) 确信它能够启动或终止相应的服务。 3) 将该脚本放置于(取决于操作系统)/etc/init.d或/usr/sbin/init.d或/etc/rc.d中。 4) 在相应的rcX.d目录中按照合理的命名方式创建链接。 6.启动和停止服务的其他方法(如果系统不支持运行级别的话) 1) 在inittab文件尾加入相应的条目。如果希望用户的rc脚本在系统刚刚就绪之后运行,使用inittab是很好的 方式。 2) 大多数系统都含有文件/etc/rc.d/(或在其他目录下),该脚本文件将在inittab和运行级别脚本之后运 行。可以在该文件中加入任何命令,或从中调用最习惯用的启动脚本。 3) 有些系统还在/bin目录下(更多的是在/usr/sbin目录下)含有一个名为shutdown的脚本文件。可以使用它来 关闭某些服务。 第29章 cgi脚本 1.本章讲授使用shell脚本编写cgi程序,此技术基本没有什么价值,省略。
版权声明:本文标题:Linux与UNIX shell编程指南 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.roclinux.cn/p/1710266099a565166.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论