linux三剑客之awk命令详解

22 篇文章 2 订阅

linux三剑客之awk命令详解

awk 是一个处理文本的编程语言工具,能用简短的程序处理标准输入或文件、数据排序、计算以及生成报表等等。awk工具主要用于格式化输出,可以用类似于处理表格的方式处理文本,也就是说可以将文本处理成表格的格式,包含行和列,然后可以执行打印某些行、打印某些列、删除某些行、删除某些列等操作。

awk与grep、sed一样均支持从管道符接受标准输入和从命令行接受参数,awk同样也支持正则表达式。
awk 处理的工作方式与数据库类似,支持对记录(行)和字段(列)处理,这也是 grep 和 sed 不能实现的。
在 awk 中,缺省的情况下将文本文件中的一行视为一个记录,逐行放到内存中处理,而将一行中的某一部分作为记录中的一个字段。用 1,2,3…数字的方式顺序的表示行(记录)中的不同字段。用$后跟数字,引用对应的字段,以逗号分隔,0 表示整个行。

基本的命令语法:awk option ‘pattern {action}’ file

功能参数+模式+动作

是不是这个语法看起来好眼熟,确实是,跟sed的语法差不多,只不过awk可以将行分割成多个字段,然后选择性的打印这些字段,而sed则只能对整行进行处理。
栗子:awk -F ':' '/root/{print $3}' /etc/passwd 在passwd配置文件中找到包含root的行并用冒号分隔成多个字段,然后打印第三个字段

[root@linuxforliuhj ~]# awk -F ':' '/root/{print $0}' /etc/passwd 
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@linuxforliuhj ~]# awk -F ':' '/root/{print $1}' /etc/passwd 
root
operator

-F:功能参数,指定每一行的分隔符为冒号,默认为空白字符
/root/:模式,正则表达式,表示只处理包含root的行
{print $3}:动作,打印第3个字段

1、功能参数

功能参数解释
-F指定分隔符
-v变量赋值

【1】指定分隔符
有如下文件

[root@linuxforliuhj test]# cat a.txt 
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
hadoop101:x:1000:1000:刘浩君的linux:/home/hadoop101:/bin/bash
hadoop102:x:1001:1002::/home/hadoop102:/bin/bash
mysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/false

以冒号分隔每一行并打印每一行的第一个字段:
cat a.txt | awk -F ':' '{print $1}'

[root@linuxforliuhj test]# cat a.txt | awk -F ':' '{print $1}'
avahi
postfix
tcpdump
hadoop101
hadoop102
mysql

此时我们只指定了冒号为分隔符,如果我想指定两个字符为分隔符呢,则需要使用[ ]将分隔符括起来
cat a.txt | awk -F '[:#]' '{print $1}'
这样在处理每一行的时候只要遇到冒号或者#号就分隔

【2】变量赋值
以冒号分隔每一行并打印第三列的值乘以3
cat a.txt | awk -F ':' -v h=3 '{print h*$3}'

[root@linuxforliuhj test]# cat a.txt | awk -F ':' '{print $3}'         
70
89
72
1000
1001
27
[root@linuxforliuhj test]# cat a.txt | awk -F ':' -v h=3 '{print h*$3}'
210
267
216
3000
3003
81

同时也可以传入变量
cat a.txt | awk -F ':' -v a=$a '{print a*$3}'

[root@linuxforliuhj test]# a=`cat a.txt | wc -l`
[root@linuxforliuhj test]# echo $a              
6
[root@linuxforliuhj test]# cat a.txt | awk -F ':' -v a=$a '{print a*$3}' 
420
534
432
6000
6006
162

主要的功能参数就只有这两个,指定分隔符和变量赋值,下面继续看模式,即对哪些行进行处理,相当于grep,但是比grep更高级一点。

2、模式
在开始讲述模式之前,我们先说一下BEGIN和END模式
BEGIN 模式是在处理文件之前执行该操作,常用于修改内置变量、变量赋值和打印输出的页眉或标题。
awk -F ':' 'BEGIN{print "用户名\t\t\t\t权限"}/root/{printf "%-30s%-30s\n", $1,$7}'

[root@linuxforliuhj test]# awk -F ':' 'BEGIN{print "用户名\t\t\t\t权限"}/root/{printf "%-30s%-30s\n", $1,$7}' /etc/passwd  
用户名                          权限
root                          /bin/bash                     
operator                      /sbin/nologin 

END则是在处理完文本之后打印的内容
awk -F ':' 'BEGIN{print "用户名\t\t\t\t权限"}/root/{printf "%-30s%-30s\n", $1,$7}END{print "--------------------\n打印结束!"}' /etc/passwd

[root@linuxforliuhj test]# awk -F ':' 'BEGIN{print "用户名\t\t\t\t权限"}/root/{printf "%-30s%-30s\n", $1,$7}END{print "--------------------\n打印结束!"}' /etc/passwd  
用户名                          权限
root                          /bin/bash                     
operator                      /sbin/nologin                 
--------------------
打印结束!

其次我们再说一下常用的awk内置变量,内置变量就相当于在awk处理文本的过程中生成的变量,例如NR表示每一行的行数,NF则表示分割后的字段数等等,如果想要改变内置变量,例如默认输出时每个字段之间的分隔符是Tap,可以在BEGIN中改变输出分隔符。

[root@linuxforliuhj test]# awk -F ':'  '/hadoop/{print $1,$3}' /etc/passwd                
hadoop101 1000
hadoop102 1001
[root@linuxforliuhj test]# awk -F ':'  'BEGIN{OFS="---"}/hadoop/{print $1,$3}' /etc/passwd   
hadoop101---1000
hadoop102---1001

awk内置变量:

变量名解释
FS分隔符,默认空格
OFS输出分隔符,默认空格
RS每一行的分隔符,默认\n
ORS输出时每一行的分隔符,默认\n
NF分割以后的字段数
NR行号
FILENAME当前输入文件名
ARGV包含命令行参数的数组
ARGC命令行参数的个数

现在开始介绍模式,模式就是我们要选择哪些行进行处理,是选择包含root的行还是前5行,我们自己可以设定

模式解释
/regexp/匹配满足正则表达式的行
+ - * / % ^加减乘除取余指数
=变量赋值
|| &&或者 并且
~ !~某个字段满足某个正则或者不满足某个正则
== >= <= != > <大于等于小于不等于

【1】匹配正则
awk -F ':' '/hadoop/{print $1,$3,$NF}' /etc/passwd
匹配包含hadoop的行并且以冒号分隔匹配到的行然后打印第1、3和最后一个字段

[root@linuxforliuhj test]# awk -F ':'  '/hadoop/{print $1,$3,$NF}' /etc/passwd
hadoop101 1000 /bin/bash
hadoop102 1001 /bin/bash
[root@linuxforliuhj test]# awk -F ':'  '/hadoop/{print $1,$3,NF}' /etc/passwd 
hadoop101 1000 7
hadoop102 1001 7
[root@linuxforliuhj test]# awk -F ':'  '/hadoop/{print $1,$3,$7}' /etc/passwd  
hadoop101 1000 /bin/bash
hadoop102 1001 /bin/bash

NF属于内置变量,代表分割后的字段数,直接打印NF的值为7,则打印$NF的值即为打印$7的值。

【2】加减乘除简单计算
head -n 20 /etc/passwd | cat -n | awk -F ':' 'NR%2==0{print $1,$3,$NF}'
打印偶数行的第1、3和最后一个字段

[root@linuxforliuhj test]# head -n 20 /etc/passwd | cat -n | awk -F ':' 'NR%2==0{print $1,$3,$NF}'
     2  bin 1 /sbin/nologin
     4  adm 3 /sbin/nologin
     6  sync 5 /bin/sync
     8  halt 7 /sbin/halt
    10  operator 11 /sbin/nologin
    12  ftp 14 /sbin/nologin
    14  systemd-network 192 /sbin/nologin
    16  polkitd 999 /sbin/nologin
    18  colord 997 /sbin/nologin
    20  saned 996 /sbin/nologin

内置变量NR为每一行的行数,当行数为偶数时,则打印偶数行的第1、3、7个字段,因为passwd位置文件条数太多了,所以为了方便只取前20行做测试。
【3】变量赋值
awk -F ':' 'BEGIN{OFS="---"}/hadoop/{print $1,$3}' /etc/passwd
变量赋值一般使用在BEGIN模式中,也就是说在awk处理文本之前,先执行BEGIN中的赋值操作,然后再处理文本。
【4】或者和并且
cat -n /etc/passwd | awk 'BEGIN{FS=":"}NR==1||NR==5{print $1,$3,$NF}'
打印第一行和第五行的某些字段则需要使用NR指定行数,行数为1或者行数为5,所以要用||隔开,同时这里在BEGIN中修改FS变量的值跟使用-F参数是一样的。

[root@linuxforliuhj test]# cat -n /etc/passwd | awk 'BEGIN{FS=":"}NR==1||NR==5{print $1,$3,$NF}'
     1  root 0 /bin/bash
     5  lp 4 /sbin/nologin

【5】某个字段匹配某个正则
awk -F ":" '$1~/hadoop/{print $1,$3,$7}' /etc/passwd
打印以冒号分割每一行并且第一个字段满足正则/hadoop/的行的第1、3、7列,使用~符号来使某个字段匹配某个正则,这也是awk比grep更高级的地方,它可以指定某个字段满足某个正则,grep则只能过滤整行。

[root@linuxforliuhj test]# awk -F ":"  '$1~/hadoop/{print $1,$3,$7}' /etc/passwd
hadoop101 1000 /bin/bash
hadoop102 1001 /bin/bash
[root@linuxforliuhj test]# awk -F ":"  '$2~/hadoop/{print $1,$3,$7}' /etc/passwd 
[root@linuxforliuhj test]#

【6】大于小于
awk -F ":" '$1~/oo/&&NR>30{print NR,$1,$3,$7}' /etc/passwd
以冒号分割每一行并且第一列字段包含oo并且行数大于30,打印行号和第1、3、7列。

[root@linuxforliuhj test]# awk -F ":"  '$1~/oo/{print NR,$1,$3,$7}' /etc/passwd
1 root 0 /bin/bash
24 setroubleshoot 993 /sbin/nologin
44 hadoop101 1000 /bin/bash
45 hadoop102 1001 /bin/bash
[root@linuxforliuhj test]# awk -F ":"  '$1~/oo/&&NR>30{print NR,$1,$3,$7}' /etc/passwd  
44 hadoop101 1000 /bin/bash
45 hadoop102 1001 /bin/bash

【7】栗子
以:分割文件并且打印第一个字段不以r开头的行:
awk 'BEGIN{FS=":"}$1!~/^r/{print $0}' /etc/passwd

以:分割文件并且打印第一个字段以r开头的行
awk 'BEGIN{FS=":"}$1~/^r/{print $0}' /etc/passwd

以:分割每一行并且打印第9行和第10行
awk 'BEGIN{FS=":"}NR==9||NR==10{print $0}' /etc/passwd

以:分割每一行并且打印行数的平方等于9的行
awk 'BEGIN{FS=":"}NR^2==9{print $0}' /etc/passwd

以:分割每一行并且打印偶数行
awk 'BEGIN{FS=":"}NR%2==0{print $0}' /etc/passwd

以:分割每一行并且打印第5行
awk 'BEGIN{FS=":"}NR==5{print $0}' /etc/passwd

以:分割每一行并且打印第5行的第三个字段
awk -F ':' 'NR==5{print $3}' /etc/passwd

以:分割每一行并且打印第一个字段为"root"的字段
awk -F ':' '$1=="root"{print $0}' /etc/passwd

以:分割每一行并且打印第2-5行
awk -F ':' 'NR>=2&&NR<=5{print $0}' /etc/passwd

以:分割字段并且打印第一个字段正则匹配hadoop101的行
awk -F ':' '$1 ~ /hadoop101/{print $0}' /etc/passwd

  • 30
    点赞
  • 234
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Operose-honeybee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值