一、查找文件命令传统上分为三种:grep、egrep、fgrep
三种命令的区别在于:fgrep是唯一支持并行匹配多个字符串的版本;而grep与egrep只能匹配单个正则表达式。
grep默认行为模式: grep == grep -F fgrep == grep -F egrep == grep -E
二、说到grep就不得不提起正则:
这里特指符合POSIX标准的正则表达式,它符合以下两个特点:
1 特定于locale的字符序列顺序和等价字符
2 不必关心系统底层的字符集
正式讲正则之前插播一小段精品广告,他们是关于sed(stream editor)、awk、Perl、Tcl、more/less等,这些工具程序都有一个共同点,就是都沿用了某一种正则表达式形式来强化本身的功能。
首先讲到的是三类特殊符号:
1 排序[..ch..]
2 等价[=e=]
3 字符集[:xxx:]
另一个是后向引用,他在寻找重复字以及匹配引号时特别好用: \(["']\).*\1 匹配以单引号或双引号括起来的字
区间表达式:将一个或两个数字,放在\{与\}之间,有三种变化:
\{n\}: 重现n次 \{n,\}: 重现至少n次 \{n,m\}: 重现n至m次(n与m的值必须介于0至RE_DUP_MAX,该值可通过命令getconf RE_DUP_MAX获得)
扩展正则表达式:
匹配单个字符,如左方括号、连字符、右方括号或是反斜杠,应该用[\ [\-\] \\]
交替,即垂直的一条线,或称为管道字符(|)。他是ERE运算符中优先级最低的。
分组,((...))。和其他字符结合起来使用时,分组还是非常好用的。举个例子:
^abcd|efgh$意思是“匹配字符串的起始处是否有abcd,或者结尾处是否有efgh”,和^(abcd|efgh)$不一样,后者表示的是“找一个正式abcd或正式efgh的字符串”。
这里要特别注意。
三、文本文件里的替换
这一小节是重点,因为里面涉及到一个很庞大的概念,即sed。sed最初的设计是用来以批处理的方式而不是交互的方式来编辑文件。然而,在Shell脚本里,sed主要用于一些简单的文本替换。
sed基本用法:
1 通常在管道(pipeline)中间使用sed,以执行替换操作。做法是使用s命令,举例如下:
sed 's/:.*//' /etc/passwd | sort -u //删除第一个冒号之后的内容及排序列表并删除重复部分
2 更新文件并备份源文件,举例如下:
假如目前hello.xml中有这样一段话,China,which is a most strong country of the world.
sed 's/China/&, the second biggest country of Asia/' < hello.xml.old > hello.xml
这样就在原来的文档中插入了一段话,同时将原有的hello.xml内容备份在文件hello.xml.old中
3 通过-e选项使用多个sed实体,例如:
sed -e 's/China/Russia/g' -e 's/strong/large/g' hello.xml > hello2.xml
不过,如果你有很多要编辑的项目,这种形式就很恐怖。所以,将编辑命令全放进一个脚本里,再使用sed搭配-f选项会更好:
$ cat hello.sed
s/China/Russia/g
s/strong/large/g
...
$ sed -f hello.sed hello.xml > hello2.xml
sed的运作原理:
命令行上的每个文件名会依次打开与读取。如果没有文件,则使用标准输入,用“-”表示。
sed逐行读取每个没减,再将读取到的行放到内存中的某个区域——称为模式空间。区域中的内容会随着编辑命令应用在其上的操作不断更新其中的内容。当所有操作完成后,sed会将模式空间的最后内容打印到标准输出,再回到开始的位置,读取下一行。
四、字段处理
其实数据也可以视为记录与字段的结合,一条记录是相关信息的单个集合,可视作数据库中的data,而字段指的就是记录的组成部分。可以看做是数据库中的field。
cut、join与awk
cut与join的用法这里不再做过多讲述,只要记住一个是剪切字段,一个是拼接字段就行了,使用的时候借助-man即可,很简单。
这里主要介绍下可以和sed平分秋色的一个重要指令——awk
awk用法:
awk主要用于取出字段并重新编排和一些简易的文本处理。但由于他本身锁提供的功能完备,已经可以算是一个很好用的程序语言了。
awk设计的重点在字段与记录上:awk读取输入记录,然后自动将各个记录切分为字段。或者,awk特别之处就是:也可以设置它为一个完整的ERE,这种情况下,每一个匹配在该ERE的文本都将视为字段分隔字符。
awk的输入、输出分隔字符用法是分开的,这点与其他工具程序不同。例如:
$ awk -F: '{ print $1, $5 }' /etc/passwd
-F选项会自动地设置FS变量。程序不必直接参照FS变量,也不用必须管理读取的记录并将它们分割为字段:awk会自动完成这些事。
$ awk -F: -v 'OFS=**' '{ print $1, $5 }' /etc/passwd
root**root
...
haldaemon**HAL daemon
avahi**Avahi daemon
avahi-autoipd**avahi-autoipd
apache**Apache
ntp**
...
$ awk -F: '{ print "User", $1, "is really", $5 }' /etc/passwd
User root is really root
...
User daemon is really daemon
User adm is really adm
User lp is really lp
User sync is really sync
...
好了,第一节先到这里。