Linux命令:grep,awk,sed

@date:2016-09-03 10:42:00

grep #

grep (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。常用来在结果中搜索特定的内容。

一般格式:

 grep [选项] 基本正则表达式 [文件]

选项 #

    -c    只输出匹配行的计数
    -i    不区分大小写(单字符)
    -h    不显示文件名(多文件时)
    -l    只输出文件名(多文件时)
    -n    显示匹配行及行号
    -s    不显示错误信息
    -v    显示不包含匹配文本的所有行

    --color=auto 自动高亮找到的关键词

示例

  1. 将/etc/passwd,有出现 root 的行取出来:
$ grep 'root' /etc/passwd

root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

# 或者
$ cat /etc/passwd | grep 'root'

2)将/etc/passwd,有出现 root 的行取出来,同时显示这些行在/etc/passwd的行号:

$ grep -n root /etc/passwd

1:root:x:0:0:root:/root:/bin/bash
30:operator:x:11:0:operator:/root:/sbin/nologin

3)将/etc/passwd,将没有出现 root 的行取出来

$ grep -v root /etc/passwd

root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

4)将/etc/passwd,将没有出现 root 和nologin的行取出来

$ grep -v root /etc/passwd | grep -v nologin

root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
  1. 查找nginx是否运行:
$ ps aux | grep nginx

www       1576  0.0  2.7  71652 28232 ?        S    Aug14   0:21 nginx: worker process

根据文件内容递归查找目录 #

6)在当前目录里文件查找字符串'math'

$ grep 'math' *

grep: my: Is a directory
grep: my1: Is a directory
s.txt:lisi 1989 male math 99
s.txt:wangxuebing 1978 male math 89
s.txt:lichang 1989 male math 99

7)在当前目录及其子目录下搜索'math'行的文件

$ grep -r 'math' * 

8)当前目录及其子目录下搜索'math'行的文件,但是不显示匹配的行,只显示匹配的文件

$ grep -l -r 'math' * 

s.txt

正则表达式 #

支持正则语法,单引号里面写正则。

正则示例:

't[ae]st' #查找test或者tast
'[^g]oo' #字符串不含有g。注意中括号里是不包含,不是以其开头
'[^a-z]oo' #字符串前不包含a-z小写字母
'[0-9]' #包含数字0-9
'^the' #匹配字母t开始的字符
'the$' #匹配字母e结尾的字符

示例:

$ grep '^xu' s.txt 

xuliang 1977 male economic 89
xuxin 1986 female english 99

更多的正则知识请查看正在相关知识。

扩展grep(grep -E 或者 egrep) #

使用扩展grep的主要好处是增加了额外的正则表达式元字符集。

示例:

查找包含1990和1989的行:

$ grep -E '1990|1989' s.txt 

lisi 1989 male math 99
wanglijiang 1990 female chinese 78
lichang 1989 male math 99
wanglijiang 1990 female chinese 78
lisibao 1989 male math 99
xiaobao 1990 female chinese 78

awk #

awk简介 #

awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件(或其他方式的输入流, 如重定向输入)逐行的读入(看作一个记录集), 把每一行看作一条记录,以空格(或\t,或用户自己指定的分隔符)为默认分隔符将每行切片(类似字段),切开的部分再进行各种分析处理。

awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk 是 AWK 的 GNU 版本。

Awk基本语法:

awk 'pattern1 {command1;command 2…; command 3}  pattern2 { command …}'

pattern表示用来过滤记录的模式,可是是正则表达式,关系运算表达式,也可以什么也没有(表示选中所有记录)。

每个pattern选中的行记录会被花括号括起来的命令command操作一遍, command之间用;分割。 花括号里面可以什么也没有, 则默认为print输出整行记录。 Comamnd可以是输出, 可以是算术运算,逻辑运算,循环控制等等。

示例 #

s.txt

zhangsan 1977 male computer 83
lisi 1989 male math 99
wanglijiang 1990 female chinese 78
xuliang 1977 male economic 89
xuxin 1986 female english 99
wangxuebing 1978 male math 89
lichang 1989 male math 99
wanglijiang 1990 female chinese 78
zhangsansan 1977 male computer 83 
langxuebing 1978 male math 89
lisibao 1989 male math 99
xiaobao 1990 female chinese 78

一行中的5个字段分辨表示姓名, 出生年, 性别,科目,分数, 是一个很传统很典型的报表文件。

现在演示awk是如何查找的:

1)直接输出1990年出生的同学:

$ awk '/1990/' s.txt

wanglijiang 1990 female chinese 78
wanglijiang 1990 female chinese 78
xiaobao 1990 female chinese 78
 

或者:

$ awk '/1990/{print $0}' s.txt

$0表示匹配所有列。

2)对chinese的课程的行输出"语文":

$ awk '/chinese/{print "语文"}' s.txt

语文
语文
语文

3)记录的头部和结尾加上一段说明:

$ awk 'BEGIN{print "Result of the quiz:\n"}{print $0}END{print "------"}' s.txt
Result of the quiz:

zhangsan 1977 male computer 83
lisi 1989 male math 99
wanglijiang 1990 female chinese 78
xuliang 1977 male economic 89
xuxin 1986 female english 99
wangxuebing 1978 male math 89
lichang 1989 male math 99
wanglijiang 1990 female chinese 78
zhangsansan 1977 male computer 83
langxuebing 1978 male math 89
lisibao 1989 male math 99
xiaobao 1990 female chinese 78
------

BEGIN只会在最开始执行;END只会在扫描所有行数之后执行。BEGIN和END之间的花括号的内容每扫描一行都会执行。

4)查找女生的成绩且只输出姓名、学科、成绩:

$ awk '$3=="female"{print $1,$4,$5}' s.txt
wanglijiang chinese 78
xuxin english 99
wanglijiang chinese 78
xiaobao chinese 78

$1表示第1列,$n类推。这里条件是表达式,而不是正则。print里,表示空格分隔符。

5)找出1990年出生的学生姓名,并要求匹配正则:

$ awk '$2~/1990/{print $1}' s.txt
wanglijiang
wanglijiang
xiaobao

这里~表示匹配正则表达式。!~表示不匹配正则表达式。

如果需要多选,则改成:

$ awk '$2~/(1990|1991)/{print $1}' s.txt
  1. 找出大于1985年出生的学生姓名,年龄,使用表达式:
$ awk '$2>"1985"{print $1,$2}' s.txt
lisi 1989
wanglijiang 1990
xuxin 1986
lichang 1989
wanglijiang 1990
lisibao 1989
xiaobao 1990

awk内置变量 #

awk有许多内置变量用来设置环境信息,这些变量可以被改变,下面给出了最常用的一些变量。

ARGC               命令行参数个数
ARGV               命令行参数排列
ENVIRON            支持队列中系统环境变量的使用
FILENAME           awk浏览的文件名
FNR                浏览文件的记录数
FS                 设置输入域分隔符,等价于命令行 -F选项
NF                 浏览记录的域的个数
NR                 已读的记录数
OFS                输出域分隔符
ORS                输出记录分隔符
RS                 控制记录分隔符

$0                 指整条记录
$1, $2, … $n      当前记录的字段

示例:
6)第四个字段科目为chinese的记录编号, 学生姓名, 科目:

$ awk '$4=="chinese"{print NR, $1, $4, $5}' s.txt

3 wanglijiang chinese 78
8 wanglijiang chinese 78
12 xiaobao chinese 78

7)统计数学成绩大于90的个数:

$ awk 'BEGIN{goodMath=0;}($4=="math" && $5>90){goodMath++}END{print goodMath}' s.txt

3

8)显示最近登录的5个帐号

$ last -n 5 | awk  '{print $1}'
root
root
root
dmtsai
root

9)更换行分隔符为;

$ cat /etc/passwd |awk  -F ':'  '{print $1}'  
root
daemon
bin
sys

-F指定域分隔符为:

10)批量操作

# 关闭所有正在运行容器
docker ps | awk  '{print $1}' | xargs docker stop

# 删除所有容器应用
docker ps -a | awk  '{print $1}' | xargs docker rm

11)文件切割

awk '{filename = "sub." int((NR-1)/5000) ".csv"; print >> filename}' history.csv

每5W行切割为一个文件。

12)分组合并

例如test.txt文本内容是:

yjc 1 20170118
yjc 1 20170118
lisi 1 20170223

需要整理成(姓名、日期相同的计数累加):

yjc 2 20170118
lisi 1 20170223

脚本:

cat test.txt | awk '{a[$1$3]["c"]+=$2;a[$1$3]["u"]=$1;a[$1$3]["d"]=$3;}END{for(i in a)print a[i]["u"],a[i]["c"],a[i]["d"]}'

sed #

和grep、awk不同,sed更侧重对搜索文本的处理,如修改、删除、替换等等。

sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。

语法

sed [-hnV][-e<script>][-f<script文件>][文本文件]

参数说明:

-e<script>或--expression=<script>     以选项中指定的script来处理输入的文本文件。
-f<script文件>或--file=<script文件>     以选项中指定的script文件来处理输入的文本文件。
-h或--help 显示帮助。
-n或--quiet或--silent 仅显示script处理后的结果。
-i  直接编辑文件而不是显示在屏幕上
-V或--version 显示版本信息。

动作说明:

a :新增, a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)~
c :取代, c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行!
d :删除,因为是删除啊,所以 d 后面通常不接任何咚咚;
i :插入, i 的后面可以接字串,而这些字串会在新的一行出现(目前的上一行);
p :列印,亦即将某个选择的数据印出。通常 p 会与参数 sed -n 一起运行~
s :取代,可以直接进行取代的工作哩!通常这个 s 的动作可以搭配正规表示法!例如 1,20s/old/new/g 就是啦!

sed命令必须跟一个动作。

新建文件t.txt:

zhangsan 1977 male computer 83
lisi 1989 male math 99
wanglijiang 1990 female chinese 78

1)新增一行:第3行后新增:

$ sed -e '3a newline'

zhangsan 1977 male computer 83
lisi 1989 male math 99
wanglijiang 1990 female chinese 78
newline

2)插入一行:第3行前插入:

$ sed -e '3i newline'

zhangsan 1977 male computer 83
lisi 1989 male math 99
newline
wanglijiang 1990 female chinese 78

3)删除一行:删除第3行:

$ sed -e '3d'

zhangsan 1977 male computer 83
lisi 1989 male math 99

4)替换一行:

$ sed -e '3c newline'

zhangsan 1977 male computer 83
lisi 1989 male math 99
newline

5)行内部分内容的替换:
格式:

sed 's/要被取代的字串/新的字串/g'

示例:

$ sed '3s/1990/2000/g' t.log 

zhangsan 1977 male computer 83
lisi 1989 male math 99
wanglijiang 2000 female chinese 78

6)多行操作:

$ sed '2,3d' t.log  #删除2,3行
$ sed '2,$d' t.log  #从第2行开始删除到末尾
$ sed '2,3a test' t.log #分别在第2行,第3行增加字符"test"

注意:
1、上述的操作均只在输出缓冲里操作,文件并没有变化;需要直接修改文件,前面加-i参数;
2、-e参数可以没有。

Xargs #

之所以能用到这个命令,关键是由于很多命令不支持|管道来传递参数,而日常工作中有有这个必要,所以就有了xargs命令,例如:

find /sbin -perm +700 |ls -l       #这个命令是错误的
find /sbin -perm +700 |xargs ls -l   #这样才是正确的

参考:
1、linux awk命令详解 - ggjucheng - 博客园
http://www.cnblogs.com/ggjucheng/archive/2013/01/13/2858470.html
2、Linux sed命令 | 菜鸟教程
http://www.runoob.com/linux/linux-comm-sed.html

Build by Loppo 0.6.14