linux 命令之 awk

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhang_referee/article/details/83099269

一直以为 awk 跟 sed 一样,只是文本处理工具,man 后才知道,awk 是一种编程语言,用于文本和数据处理。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出,支持正则非常强大。

命令基本形式为:

awk option 'script' file1 file2 ...
awk option -f scriptfile file1 file2 ...

awk缺省的行分隔符是换行,缺省的列分隔符是连续的空格和Tab

下面从一个小栗子开始awk

我们可以使用 awk 工具输出网站访问 ip ,先看下示例数据

那么我们接下来,输入访问网站的ip ,这里只取前 10 行 

root@iZwz92skyZ:# awk '{print $1}' test.log | head -n10
113.87.162.10
113.87.162.10
113.87.162.10
113.87.162.10
113.87.162.10
113.87.162.10
113.87.162.10
113.87.162.10
113.87.162.10
113.87.162.10
root@iZwz92skyZ:# 

接下来,我们看下/etc/passwd 这个文件

扫描二维码关注公众号,回复: 3698995 查看本文章

可以看到,这个文件,跟我们的网站访问日志文件不同:这个文件是以" : "分割的

接下来我们尝试用awk 工具,提取出最后一列(第7列)

root@zhang:/home/zhang# awk '{print $7}' /etc/passwd



你会发现,当操作完后,一片空白,wtf ?

前面说了,awk缺省的行分隔符是换行,缺省的列分隔符是连续的空格和Tab ,不过不要着急,强大的awk 的分隔符可以自定义。

-F fs   fs指定输入分隔符,fs可以是字符串或正则表达式

root@zhang:/home/zhang# awk -F: '{print $7}' /etc/passwd

 还可使用:

root@zhang:/home/zhang# awk '{FS=":"} {print $7}' /etc/passwd

上面的是等价的 

举个正则的栗子,比如我们统计代码中有多少空行。

这里拿/etc/init.d/mysql 文件为例

root@zhang:/home/zhang# awk '/^ *$/{count=count+1} END {print count}' /etc/init.d/mysql
49
root@zhang:/home/zhang# 

这里说下awk 的模式

  1. 模式可以是以下任意一个:
  2.  /正则表达式/:使用通配符的扩展集。
  3.     关系表达式:使用运算符进行操作,可以是字符串或数字的比较测试。
  4.     模式匹配表达式:用运算符~(匹配)和~!(不匹配)。
  5.     BEGIN语句块、pattern语句块、END语句块。

操作由一个或多个命令、函数、表达式组成,之间由换行符或分号隔开,并位于大括号内,主要部分是:

  1.     变量或数组赋值
  2.     输出命令
  3.     内置函数
  4.     控制流语句

上面: awk '/^ *$/{count=count+1} END {print count}' /etc/init.d/mysql 解释:

 首先:^ (空格)$ 表示以空格开始,匹配多个空格并以空格结束,也就是匹配一个空白行。紧接着定义了一个计数器变量,每当匹配到满足条件行时,累加,然后当awk 读至文件末时, 执行 print count 。

下面我们使用awk 来统计当前系统账号数:

root@iZwz92Z:~# awk 'BEGIN {count=0;} {count++;print$0;} END {printf "current system user count is:%s\n",count}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-timesync:x:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false
systemd-network:x:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false
systemd-resolve:x:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false
systemd-bus-proxy:x:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false
syslog:x:104:108::/home/syslog:/bin/false
_apt:x:105:65534::/nonexistent:/bin/false
messagebus:x:106:110::/var/run/dbus:/bin/false
uuidd:x:107:111::/run/uuidd:/bin/false
ntp:x:108:114::/home/ntp:/bin/false
sshd:x:109:65534::/var/run/sshd:/usr/sbin/nologin

apache:x:1001:1001::/home/apache:/sbin/nologin
mysql:x:1002:1002::/home/mysql:/sbin/nologin
current system user count is:31

这里说下,awk 的工作原理:

   awk 'BEGIN{ commands } pattern{ commands } END{ commands }'

  1. 第一步:执行BEGIN{ commands }语句块中的语句;
  2. 第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ commands }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
  3. 第三步:当读至输入流末尾时,执行END{ commands }语句块。

BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中。
END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块。
pattern语句块中的通用命令是最重要的部分,它也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块。

一个比较常见的需求是,统计访问网站前n 个 ip 。

root@iZ0ok4oZ:# echo "这里统计访问排名前 10 的 ip"
这里统计访问排名前 10 的 ip
root@iZ0ok4oZ:# awk '{print $1}' test.log | uniq -c | sort -n | tail -n10
     10 113.87.162.10
     10 117.136.12.126
     19 113.87.162.10
     26 113.87.162.10
     41 113.87.162.10
     44 113.87.162.10
     49 113.110.231.90
     51 47.99.59.12
    184 113.87.162.10
    462 113.87.162.10

解释:

 先提取出 ip ,然后 uniq -c (在上条命令的基础上统计每行重复的次数) ,在 sort -n (指定按数值大小排序),然后tail -n (只取后10行数据) 。

上面的命令可以替换成下面的:

root@iZwz92oZ:# awk '{print $1}' test.log | uniq -c | sort -nr | head -n10
    462 113.87.162.10
    184 113.87.162.10
     51 47.99.59.12
     49 113.110.231.90
     44 113.87.162.10
     41 113.87.162.10
     26 113.87.162.10
     19 113.87.162.10
     10 117.136.12.126
     10 113.87.162.10

下面是上面命令中涉及到的命令的解释及常用参数:

sort 按字符进行比较
sort [option] file...

  1.    -f: 忽略字符大小写;
  2.     -n: 比较数值大小;
  3.     -t: 指定分隔符
  4.     -k: 指定分隔后进行比较字段
  5.     -u: 重复的行,只显示一次;
  6.     -r: 以相反的顺序来排序;

   
uniq 移除重复的行

  1. -c:显示每行重复的次数
  2. -d:仅显示重复过的行
  3. -u: 仅显示不曾重复的行

由于awk 工具的强大及内容的繁多性,这里只介绍这么多,至于更详细的文档,请参考 man awk ,或者 http://man.linuxde.net/awk 。

猜你喜欢

转载自blog.csdn.net/zhang_referee/article/details/83099269