在 shell 编程中,常需要处理文本,这里介绍几个文本处理命令。
一、grep 命令
grep 命令由来已久,用 grep 命令来查找 文本十分方便。在 POSIX 系统上,grep 可以在两种正则表达式风格中选择一种(BRE 和 ERE),或是执行简单的字符串匹配。传统上,有三种程序可以用来查找整个文本文件:
1)grep:最早的文本匹配程序。使用 POSIX 标准定义的基本正则表达(Basic Regular Expression,BRE);
2)egrep:扩展 grep。使用扩展正则表达式(Extended Regular Expression,ERE);
3)fgrep:快速 grep。匹配固定字符串而非正则表达式,它使用优化的算法,能更有效地匹配固定字符串。
在目前的 POSIX 标准中,这三个程序已经被整合成为一个程序 grep,通过对 grep 命令加以不同的选项进行选择控制。
grep 命令由一个选项、一个要匹配的模式和要搜索的文件组成,语法如下:
grep [options] PATTERN [FILES]
如果没有提供文件名,则 grep 命令将搜索标准输入。grep 命令将会根据所提供的模式对文件进行匹配,发现匹配查找模式的行时,将该行显示出来。当 grep 命令同时搜索多个文件时,将会在搜索结果每一行前面加上文件名与一个冒号。grep 命令的主要选项如下:
| 选项 | 功能 |
| -E | 使用扩展正则表达式进行匹配(取代传统的 egrep 命令) |
| -F | 使用固定字符串进行匹配(取代传统的 fgrep 命令) |
| -c | 输出匹配行的数目,而不是输出匹配的行 |
| -h | 取消每个输出行的普通前缀,即匹配查询模式的文件名 |
| -i | 忽略大小写 |
| -l | 只列出包含匹配行的文件名,而不输出真正的匹配行 |
| -v | 对匹配模式取反,即搜索匹配不到的行 |
| -n | 输出行号 |
用例子演示一下:
[tongye@localhost ~]$ grep -ni ROOT /etc/passwd 1:root:x:0:0:root:/root:/bin/bash 10:operator:x:11:0:operator:/root:/sbin/nologin
该命令将会在 /etc/passwd 中查找有 root 的行,并将该行显示出来, -n 选项输出行号,-i 选项忽略大小写。
二、sed 命令
sed( stream editor 流编辑器) ,可以用来在管道或者命令序列中编辑数据。sed 的语法如下:
sed option command file
其中,command 是命令部分,用来指示 sed 该执行何种操作,file 则是 sed 命令将要操作的对象,通常是一个文件,如果没有文件,则使用标准输入。option 是 sed 命令可以使用的选项,主要有三个选项: -n、-e、-f,在后面再介绍。
sed 命令读取每一个文件,一次读一行,将读取的行放到内存的一个区域--称为模式空间(pattern space),所有编辑上的操作都会应用到模式空间的内容。当所有操作完成后,sed 命令会将模式空间的最后内容打印到标准输出,再回到开始处,读取另一个输入行。为了演示 sed 命令,笔者写了一小段文本 test.txt 用作试验的素材(英语差,语法问题请忽略)
hello,my name is tongye I want to write a program named HelloWorld.c now,let`s begin #include "stdio.h" main(){ printf("Hello world"); } oh,it`s symple writed by tongye end
2.1 使用 s 参数执行替换操作
sed 命令一个常用的功能是进行替换操作,sed 替换操作的一般格式如下:
sed 's/string1/string2/' file # 将文件中每行的第一个 string1 替换成 string2
在上述语句中,参数 s 表示这是一个替换操作,/ 字符是界定符,用于分隔正则表达式与替代文本。界定符可以是任何可显示的字符,但是 / 字符是最常用的界定符。另外,在处理文件名称时,一般使用分号、冒号或逗号作为界定符。string1 是被替换的文本,可以是正则表达式;string2 是替换文本。
[tongye@localhost Shell_Program]$ sed 's/tongye/ttyezi/' test.txt hello,my name is ttyezi I want to write a program named HelloWorld.c now,let`s begin #include "stdio.h" main(){ printf("Hello world"); } oh,it`s symple writed by ttyezi end
需要注意的是,上述语句只能替换第一个匹配到的文本,若想要将每一个匹配到的文本都替换掉,需要在结尾加上 g 参数(global),即:
sed 's/string1/string2/g' file # 将文件中所有的 string1 都替换成 string2
如果需要删除文本中的一个字符串,可以在替换文本处不放入任何文本(即空)来实现,如下:
sed 's/string1//g' file # 删除文件中所有的 string1
2.2 使用 -e 选项和 -f 选项同时执行多个编辑命令
当 sed 后面需要同时接多个编辑命令的时候,需要使用 -e 选项。每一个编辑命令都使用一个 -e 选项,如:
[tongye@localhost Shell_Program]$ sed -e 's/tongye/ttyezi/g' -e 's/HelloWorld/helloworld/g' test.txt hello,my name is ttyezi I want to write a program named helloworld.c now,let`s begin #include "stdio.h" main(){ printf("Hello world"); } oh,it`s symple writed by ttyezi end
当需要编辑的项目很多时,如果把每一个编辑命令都接到 sed 后面,无疑会让代码很复杂,不易阅读且容易出错。这时,可以将所有的编辑命令都写进一个脚本,再使用 sed 搭配 -f 选项来操作:
# substitute.sed 存放着编辑命令 s/tongye/ttyezi/g s/HelloWorld/helloworld/g s;^\(.\).*\1$;The first letter of this line is the same as its last letter; [tongye@localhost Shell_Program]$ sed -f substitute.sed test.txt hello,my name is ttyezi I want to write a program named helloworld.c The first letter of this line is the same as its last letter #include "stdio.h" main(){ printf("Hello world"); } oh,it`s symple writed by ttyezi end