awk是功能强大的模式分析与处理语言,其名字来源于该工具的作者Alfred Aho、Peter Weinberger和Brian Kernighan 姓氏的首个字母。我们前面学习的grep命令擅长模式查找,sed命令擅长内容编辑,而awk则擅长分析文本并按规定格式输出。awk本身是一门编程语言,有自己的控制结构和变量。
awk处理文本时类似于sed,也是一行一行的处理。一行称为一个记录,每行中由指定字符分割的一个字段称为域。
文本模式扫描及处理
awk [option] -f program-file file
awk [option] program-text file
-f program-file 从program-file中读取程序脚本 -F fs 使用fs(field separator)作为输入文本域的分隔符
awk的调用方式有3种:
1. 命令行方式 awk [-F fs] 'commands' input-file(s) 其中,commands是真正awk命令,[-F fs]是可选的。 input-file(s) 是待处理的文件。 文件的每一行中,由域分隔符分开的每一项称为一个域。在没有-F定义域分隔符的情况下, 默认的域分隔符是空格。 2. 命令行调用awk脚本文件方式(将所有的awk命令保存到一个单独文件,然后调用): awk -f program-file input-file(s) 其中,-f选项加载program-file中的awk脚本,input-file(s)同上。 3. shell脚本方式 将awk命令保存到一个文件,给文件添加可执行权限,并在首行定义awk为命令解释器: #!/bin/awk
我们首先来看一个最常见的awk应用:
[peter@ibi98 tr]$ ls -l 总用量 12 -rw-rw-r-- 1 peter peter 241 3月 16 10:44 demo_wc -rw-rw-r-- 1 peter peter 708 3月 16 11:46 demo_wc_2 -rw-rw-r-- 1 peter peter 183 3月 16 17:00 demo_wc_3 [peter@ibi98 tr]$ ls -l |awk '{print $3}' peter peter peter [peter@ibi98 tr]$ ls -l |awk '{print $6}' 3月 3月 3月
上面的例子中,在“3月”前面有两个空格,由此可见awk默认把连续的空格作为一个域分隔符。第一行只有两个域,所以打印第三和第六个域时第一行都是空行。
如果域分隔符不是空格,可以用-F定义:
[peter@ibi98 xiezy]$ head -3 /etc/passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin [peter@ibi98 xiezy]$ head -3 /etc/passwd |awk -F ':' '{print $1}' root bin daemon
awk命令格式为'[/pattern/]{action}'(方括号表示可以省略),即包括匹配模式和操作两部分,如果在一行中匹配到模式pattern,就对该行执行操作action;如果省略匹配模式部分,则对每一行都执行操作。我们还用上面的例子,加上模式匹配部分:
[peter@ibi98 xiezy]$ head -3 /etc/passwd |awk -F ':' '/root/{print $1}'
root
awk只输出包含模式“root”的行的第一个域的内容。
a是一种编程语言,其控制结构与C语言类似,如:
[peter@ibi98 awk]$ cat demo_awk #Seq Taxa ChrNum Species 1 plant 5 Arabidopsis thaliana 2 plant 12 Oryza sativa 3 animal 24 Homo sapiens 4 animal 20 Mus musculus [peter@ibi98 awk]$ awk -F'\t' '{if($1 !~ /^#/ && $3>10) {print $1,$3,$4}}' demo_awk 2 12 Oryza sativa 3 24 Homo sapiens 4 20 Mus musculus
awk判断如果不是注释行(行首有#)且染色体数大于10,就输出序号、染色体数和物种名。
awk有一些内置变量,可以不用定义直接使用。awk的内置变量有:
ARGC 命令行参数个数 ARGV 命令行参数排列 ENVIRON 支持队列中系统环境变量的使用 FILENAME awk浏览的文件名 FNR 浏览文件的记录数 FS 设置输入域分隔符,等价于命令行 -F选项 NF 浏览记录的域的个数 NR 已读的记录数 OFS 输出域分隔符 ORS 输出记录分隔符 RS 控制记录分隔符
下面的例子直接使用内置变量,NR是记录的序号,OFS定义输出的域的分隔符为制表符:
[peter@ibi98 awk]$ last -10 |awk '{OFS="\t";print NR,$1,$3}' |grep 'wang'
7 wangling 172.22.42.84
9 wangling 172.22.42.84
注意上面例子中awk命令外层是单引号,内层只能用双引号,再用单引号配对就会出错。
awk还经常用来选择和调整列的位置,用来为数据库的表准备数据:
[peter@ibi98 awk]$ cat demo_awk #Seq Taxa ChrNum Species 1 plant 5 Arabidopsis thaliana 2 plant 12 Oryza sativa 3 animal 24 Homo sapiens 4 animal 20 Mus musculus [peter@ibi98 awk]$ cat demo_awk |grep -v "^#" |awk -F'\t' '{OFS="\t";print $1,$4,$3}' 1 Arabidopsis thaliana 5 2 Oryza sativa 12 3 Homo sapiens 24 4 Mus musculus 20
与前面的例子不同,该例中先用grep命令过滤掉注释行(Linux完成同一任务有多种方法,如果一个命令完成不了的,可以考虑该命令的选项是否提供该功能,如果还不行,再将不同的命令用管道组合起来,就可以完成大多数文本处理任务),再用awk处理。awk选择性输出4个字段(域)中的3个,并且将原来第4个字段调整到原来第3个字段前面。