Linux:三剑客awk、grep、sed

437 阅读7分钟

1 awk基础入门

1.1 awk简介

awk不仅仅时linux系统中的一个命令,而且是一种编程语言,可以用来处理数据和生成报告 (excel)。处理的数据可以是一个或多个文件,可以是来自标准输入,也可以通过管道获 取标准输入,awk可以在命令行上直接编辑命令进行操作,也可以编写成awk程序来进行更 为复杂的运用。

1.2 awk格式

  • awk指令是由模式,动作,或者模式和动作的组合组成。
  • 模式既pattern,可以类似理解成sed的模式匹配,可以由表达式组成,也可以是两个正斜杠之间的正则表达式。比如NR==1,这就是模式,可以把他理解为一个条件。
  • 动作即action,是由在大括号里面的一条或多条语句组成,语句之间使用分号隔开。比如awk使用格式:
awk [options] 'pattern {action}' file
[options]:awk参数
pattern:找谁,即模式,也可以理解为条件,也叫找谁,你找谁?高矮,胖瘦,男女?
action:干啥,即动作,可以理解为干啥,找到人之后你要做什么。

image.png

1.3 使用范例

范例1-1:基本的模式和动作

[root@ray ~]# awk -F ":" 'NR>=2' && NR<=6{print NR,$1}' /etc/passwd2 bin3 daemon4 adm5 lp6 sync
命令说明:
-F 指定分隔符为冒号,相当于以“:”为菜刀,进行字段的切割。 
NR>=2 && NR<=6:这部分表示模式,是一个条件,表示取第2行到第6行。 
{print NR,$1}:这部分表示动作,表示要输出NR行号和$1第一列。

范例1-2:只有模式

[root@ray ~]#awk -F ":" 'NR>=2&&NR<=6' /etc/passwdbin:x:1:1:bin:/bin:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologinadm:x:3:4:adm:/var/adm:/sbin/nologinlp:x:4:7:lp:/var/spool/lpd:/sbin/nologinsync:x:5:0:s
命令说明:
-F指定分隔符为冒号 NR>=2&&NR<=6这部分是条件,表示取第2行到第6行。 但是这里没有动作,这里大家需要了解如果只有条件(模式)没有动作,awk默认输出整行

范例1-3:只有动作

[root@ray ~]# awk -F ":" '{print NR,$1}' /etc/passwd1 root2 bin3 daemon4 adm5 lp6 sync7 shutdown8 halt 9 mail10 uucp 以下省略....
命令说明: 
-F指定分隔符为冒号 这里没有条件,表示对每一行都处理 
{print NR,$1}表示动作,显示NR行号与$1第一列 这里要理解没有条件的时候,awk会处理每一行。

范例1-4:多个模式和动作

[root@ray ~]# awk -F ":" 'NR==1{print NR,$1}NR==2{print NR,$NF}' /etc/passwd1 root2 /sbin/nologin 
命令说明: 
-F指定分隔符为冒号 这里有多个条件与动作的组合 
NR==1表示条件,行号(NR)等于1的条件满足的时候,执行{print NR,$1}动作,输出行号与第一列。 
NR==2表示条件,行号(NR)等于2的条件满足的时候,执行{print NR,$NF}动作,输出行号与最后一列($NF

注意:

  • Pattern和{Action}需要用单引号引起来,防止shell作解释。
  • Pattern是可选的。如果不指定,awk将处理输入文件中的所有记录。如果指定一个模式,awk则只处理匹配指定的模式的记录。
  • {Action}为awk命令,可以是但个命令,也可以多个命令。整个Action(包括里面的所有命令)都必须放在{ 和 }之间。
  • Action必须被{ }包裹,没有被{ }包裹的就是Patern file要处理的目标文件。

1.4记录和字段

新概念记录和字段,这里为了方便大家理解可以把记录就当作行即记录==行,字段相当于列,字段==列。

名称含义
record记录,行
field域,区域,字段,列

1.4.1 记录(行)

查看下面这段文字

root:x:0:0:root:/root:/bin/bashbin:x:1:1:bin:/bin:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologinadm:x:3:4:adm:/var/adm:/sbin/nologinlp:x:4:7:lp:/var/spool/lpd:/sbin/nologinsync:x:5:0:sync:/sbin:/bin/syncshutdown:x:6:0:shutdown:/sbin:/sbin/shutdownhalt:x:7:0:halt:/sbin:/sbin/haltmail:x:8:12:mail:/var/spool/mail:/sbin/nologinuucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin

思考:一共有多少行,你如何知道的,通过什么标志?

awk对每个要处理的输入数据认为都是具有格式和结构的,而不仅仅是一堆字符串。默认情况下,每一行内容都是一条记录,并以换行符分隔(\n)结束

1.4.2 企业面试题:按单词出现频率降序排序(计算文件中每个单词的重复数量)

注:(此处使用sort与uniq即可) 题目:

[root@ray dir]# sed -r '1,10s#[^a-zA-Z]+# #g' /etc/passwd>~/dir/count.txt
[root@ray dir]# cat ~/dir/count.txt
root x root root bin bash
bin x bin bin sbin nologin
daemon x daemon sbin sbin nologin
adm x adm var adm sbin nologin
lp x lp var spool lpd sbin nologin
sync x sync sbin bin sync
shutdown x shutdown sbin sbin shutdown
halt x halt sbin sbin halt
mail x mail var spool mail sbin nologin
operator x operator root sbin nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
libstoragemgmt:x:998:997:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
ntp:x:38:38::/etc/ntp:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
chrony:x:997:995::/var/lib/chrony:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
syslog:x:996:994::/home/syslog:/bin/false
mysql:x:1000:1000::/home/mysql:/sbin/nologin
oldboy:x:1001:1001::/home/oldboy:/bin/bash
testuser:x:1002:1002::/home/testuser:/bin/bash
[root@ray dir]# 

思路: 让所有单词排成一列,这样每个单词都是单独的一行

  1. 设置RS值为空格
  2. 将文件里面的所有空格替换为回车换行符“\n”
  3. grep所有连续的字母,grep -o参数让他们排成一列。 解题:
[root@ray dir]# awk 'BEGIN{RS="[ ]+"}{print $0}' count.txt |sort |uniq -c|sort
      1 
     10 x
     12 sbin
      1 abrt:x:173:173::/etc/abrt:/sbin/nologin
      1 account
      1 bash
      1 bus:/:/sbin/nologin
      1 chrony:x:997:995::/var/lib/chrony:/sbin/nologin
      1 Daemon:/var/lib/rpcbind:/sbin/nologin
      1 dbus:x:81:81:System
      1 ftp:x:14:50:FTP
      1 games:x:12:100:games:/usr/games:/sbin/nologin
      1 libstoragemgmt:/var/run/lsm:/sbin/nologin
      1 libstoragemgmt:x:998:997:daemon
      1 lpd
      1 Management:/:/sbin/nologin
      1 message
      1 mysql:x:1000:1000::/home/mysql:/sbin/nologin
      1 Network
      1 nobody:x:99:99:Nobody:/:/sbin/nologin
      1 ntp:x:38:38::/etc/ntp:/sbin/nologin
      1 oldboy:x:1001:1001::/home/oldboy:/bin/bash
      1 polkitd:/:/sbin/nologin
      1 polkitd:x:999:998:User
      1 postfix:x:89:89::/var/spool/postfix:/sbin/nologin
      1 rpc:x:32:32:Rpcbind
      1 sshd:x:74:74:Privilege-separated
      1 SSH:/var/empty/sshd:/sbin/nologin
      1 syslog:x:996:994::/home/syslog:/bin/false
      1 systemd-network:x:192:192:systemd
      1 tcpdump:x:72:72::/:/sbin/nologin
      1 testuser:x:1002:1002::/home/testuser:/bin/bash
      1 User:/var/ftp:/sbin/nologin
      2 daemon
      2 for
      2 lp
      2 operator
      2 spool
      3 adm
      3 halt
      3 mail
      3 shutdown
      3 sync
      3 var
      4 root
      5 bin
      6 nologin

2 grep:文本过滤工具

2.1 命令详解

【功能说明】grep命令是Linux最重要的命令之一,其功能是从文本文件或者管道数据流中筛选匹配的行及数据,如果再配和正则表达式的技术一起使用,则功能更为强大。

【语法格式】grep语法如下:

grep [options] pattern file
      参数      匹配模式 查找的文件

grep命令里的匹配模式或模式匹配,都是你想要找的东西,可以是普通文字符号,也可以是正则表达式。

【选项说明】grep命令的参数选项及说明

image.png

2.2 使用范例

范例2-1:请使用grep过滤不包含stu的字符串的行(-v)。

[root@ray dir]# cat test.txt 
stu10309
123456
stu10312
234567
stu10322
345678
stu10324
456789
[root@ray dir]# grep -v "stu" test.txt 
123456
234567
345678
456789
[root@ray dir]# 

范例2-2:使用grep显示过滤后的内容的行号(-n)

[root@ray dir]# cat test.txt 
stu10309
123456
stu10312
234567
stu10322
345678
stu10324
456789
[root@ray dir]# grep -n "stu" test.txt 
1:stu10309
3:stu10312
5:stu10322
7:stu10324
[root@ray dir]# 

范例2-3:不区分大小写参数实践(-i)。

[root@ray dir]# cat test.txt 
STU0
stu10309
123456
stu10312
234567
stu10322
345678
stu10324
456789
[root@ray dir]# grep -i "stu" test.txt 
STU0
stu10309
stu10312
stu10322
stu10324
[root@ray dir]# 

范例2-4:同时过滤两个不同的字符串并为过滤的内容显示颜色(-E和--color参数)

[root@ray dir]# grep -Ei "stu|456" test.txt 
STU0
stu10309
123456
stu10312
234567
stu10322
345678
stu10324
456789
[root@ray dir]# grep -Ei --color=auto "stu|456" test.txt 
STU0
stu10309
123456
stu10312
234567
stu10322
345678
stu10324
456789
[root@ray dir]# 

3 sed:字符流编辑器

3.1 命令详解

【功能说明】sed是操作、过滤、转换文本内容的强大工具,常用功能包括对文件实现快速增删改查,其中查询的功能中最常用的是过滤(过滤指定字符串)、取行(取出指定的行)。

【语法格式】

sed [选项] [sed内置命令字符] [输入文件]

sed命令参数 image.png sed的内置命令字符用于实现对文件进行不同的操作功能,例如对文件的增删改查等。

image.png

3.2 使用范例

3.2.1 基础范例

为了更好的测试sed命令的用法,准备测试的内容文件如下:

[root@ray dir]# cat persons.txt 
101,oldboy,CEO
102,zhangyao,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
[root@ray dir]# 

范例3-1:在文件指定行后面追加文本(使用sed内置命令a)

[root@ray dir]# sed '2a 106,dandan,CSO' persons.txt 
101,oldboy,CEO
102,zhangyao,CTO
106,dandan,CSO
103,Alex,COO
104,yy,CFO
105,feixue,CIO
[root@ray dir]# 

命令解说:
2a:2表示对第二行进行操作,其他行忽略,a表示追加,2a即在第2行后追加文本

范例3-2:在文件指定行前插入文本(使用sed内置命令i)

[root@ray dir]# sed '2i 106,dandan,CSO' persons.txt 
101,oldboy,CEO
106,dandan,CSO
102,zhangyao,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CIO

命令解说:
2i:2表示对第二行进行操作,其他行忽略,i表示插入,2i即在第2行插入文本

4 企业面试题

4.1 面试题1:邮箱的正则表达式

思考:邮箱格式:aaa@qq.com

/^([A-Za-z0-9_\-\.])+@([A-Za-z0-9_\-\.])+([A-Za-z]{2,4})$/

思路解析:
分析邮件名称部分:
26个大小写英文字母表示为a-zA-Z
数字表示为0-9
下划线表示为_
中划线表示为-
由于名称是由若干个字母、数字、下划线和中划线组成,所以需要用到+表示多次出现

分析域名部分:
 一般域名的规律为“[N级域名][三级域名.]二级域名.顶级域名”,比如“qq.com”、“www.qq.com”、“mp.weixin.qq.com”、“12-34.com.cn”,分析可得域名类似“** .**  .** .**”组成。

4.2 面试题2:统计出现的次数,并按次数的倒序进行排列

Linux系统中有个文本,每行格式如下:
12.12.13.14,mac,备注1
23.22.34.15,win,备注2
12.13.13.14,mac,备注3
12.12.13.14,mac,备注1
12.12.13.14,mac,备注1
12.13.13.14,mac,备注31
12.13.13.14,win,备注2
....
用shell取出ip并统计ip重复出现的次数,并将出现次数按照次数倒序排列(可用其他语言)

思考:用cat命令查出文件内容,用sort排序、uniq去重、

[root@ray dir]# cat ip.txt|awk -F ',' '{print $1}'|sort|uniq -c|sort -rn
      3 12.13.13.14
      3 12.12.13.14
      1 23.22.34.15
[root@ray dir]# 
命令解析:
awk -F ',' '{print $1}':-F指定字段分隔符(用逗号分割),{print $1}取第一部分
uniq -c:去重
sort -rn:倒序排列

4.3 面试题3:

[root@ray dir]# cat sun.txt
孙权,21岁,男
曹操,30岁,男
现在需要将字符串abcdef放到孙权的前面,且需要放在同一行进行字符串连接,得到结果为如下:
abcdef孙权,21岁,男
曹操,25岁,男
如何用sed命令实现?

答案:

[root@ray dir]# sed -i 's/孙权/abcdef&/' sun.txt
[root@ray dir]# cat sun.txt 
abcdef孙权,21岁,男
曹操,30岁,男
[root@ray dir]# 

4.4 面试题4:如何用Linux命令或shell写个查询.svn的文件并且删除掉?

[root@ray dir]#find . -type d -name '.svn' | xargs rm -rf