shell基础 -- grep、sed、awk命令简介
在 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
2.3 使用 -n 选项与 p 参数打印特定的行
sed 默认情况下会把输入的每一行都打印到标准输出上,如果不想输出所有行,可以使用 -n 选项。使用了 -n 选项的 sed 命令将不打印任何行, -n 选项通常与参数 p 配合起来使用,p 参数可以让 sed 命令打印出符合指定范围或模式的所有行:
[tongye@localhost Shell_Program]$ sed -n 's/tongye/ttyezi/p' test.txt hello,my name is ttyezi writed by ttyezi
该语句将文件中的 tongye 替换成 ttyezi,并且只打印发生替换操作的两行;
[tongye@localhost Shell_Program]$ sed -n '1,3p' test.txt # 打印 1 到 3 行 hello,my name is tongye I want to write a program named HelloWorld.c now,let`s begin [tongye@localhost Shell_Program]$ sed -n '4p' test.txt # 只打印第 4 行 #include "stdio.h"
使用 sed -n '1,3p' 来只打印文件的前三行,注意这里的 '1,3' 表示的是一个范围;
[tongye@localhost Shell_Program]$ sed -n '/HelloWorld/p' test.txt I want to write a program named HelloWorld.c
该命令只打印包含 HelloWorld 的行。
2.4 使用 d 参数执行删除操作
要删除某一个特定的行,可以使用参数 d,只需要指定行号或者行范围,就可以从输入中删除指定的行:
[tongye@localhost Shell_Program]$ sed '1,4d' test.txt # 删除第 1 到 4 行,然后将剩余的行打印到标准输出 main(){ printf("Hello world"); } oh,it`s symple writed by tongye end
sed 也可以使用参数 d 来删除符合匹配模式的行:
[tongye@localhost Shell_Program]$ sed '/tongye/d' test.txt # 删除所有含有 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 end
2.5 使用 -i 选项或输出重定向来保存 sed 编辑的内容
在上面的所有操作中,我们发现虽然 sed 操作确实完成了,输出到标准输出上的文本内容确实发生了变化,但是如果我们再次打开所编辑的文件,会发现文件内容并没有发生更改。如果需要保存 sed 编辑的内容,可以使用 -i 选项:
[tongye@localhost Shell_Program]$ sed -i 's/tongye/ttyezi/' test.txt [tongye@localhost Shell_Program]$ cat 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