简介

awk是用于基本文本处理的工具。一般遇到复杂格式等的处理问题时,应该优先想到使用awk。比awk更加高端的,还有perl语言,它专门用于文本处理。python也有丰富的文字处理功能,但是这是它的一个小部分功能,只用python处理文本有点小题大做了。一般情况下,awk是首选。awk特别适合那些一行有多个列、而且列之间有特定分隔号分开的情况。

sed类似,awk不改变原来的文件,只是读取原来的文件的输入,然后产生新的输出。注意,awk读取标准输入的内容作为输入;如果打开文件,那么awk把文件内容作为标准输入。

基本语法

举个例子:

awk '{print $1}' ./log.txt
awk '{print $1 "\t" $3}' ./log.txt

第一个命令中,单引号内部的内容表示要执行的脚本,$1表示每行的第一列。第二个命令中\t表示输出的时候显式添加制表符,之后再输出第三列。

同时,我们可以显式的改变文本的分隔符,使用-F命令实现。举个例子,一个文本中如果如下格式的行:

root:x:0:0:root:/root:/bin/bash

我们想要以:为分隔符,那么执行下面的命令:

awk -F":" `{print "USER: " $1 "\tSHELL: " $7}` ./log.txt

会输出

USER: root    SHELL: bash

可以设置多个分隔符甚至正则表达式来分隔文本:

awk -F"[\t ]+" '{print "DEVICE: "$1 "\tFSTYPE " $3}' /etc/fstab

[\t ]有一个制表符和一个空格,+表示前边的符号出现一次或者多次。在这里,说明分隔符是至少一个的制表符或者空格。

语言特性

代码结构

awk需要有初始化的设置,这些在BEGIN代码块中;在逻辑代码结束后,还可以有END代码块,这些作为善后处理的工作。

实际例子:

BEGIN {
	FS=":"
}
{
	print "USER: " $1 "\tSHELL" $7
	/nologin/ {++adder}
}
END {
	print "'nologin' appears " adder "times."
}

BEGIN代码块中,我们声明了:作为分隔符。之后的一段是执行代码块,print语句是输出内容,/nologin/表示一个正则式,匹配nologin单词,匹配上了就个adder自增一次。END代码块在程序结束时,输出正则匹配的次数。

注意在上述的正则式中,只有匹配上相应的正则式,后面的代码才会执行,也就是说awk只对匹配上的文本感兴趣。

变量与数组

awk有用户变量和自建变量,用户变量使用时不用提前声明,比如上述的adder,可以任务awk这个特性和shell一样。变量初始化的时候默认都是空字符串,如果涉及到数值运算,则默认为0,变量对大小写敏感。

还有内建变量,给出一个常用内建变量表:

python使用awk awk和python_LinuxShell


数组命名与变量命名风格一致,也是直接使用。awk的数则可以在方括号内以任意的数字或者字符串表达式作为索引,可以把它视为一个哈希映射,查找、插入和删除的复杂度都是python使用awk awk和python_LinuxShell_02

同时,awk数组的存储空间会自动增长,存储数据的类型是任意的,而且存储的模式是稀疏存储。如果不需要使用,直接执行delete array[index]即可删除,delete array是删除整个数组。变量名不能和数组重名。

例如:

site[google] = ""
site[youtube] = ""
site[baidu] = "www.baidu.com"
site[1] = 123

awk通过ENVIRON数组访问环境变量

举个例子:

awk 'BEGIN{print ENVITON["HOME"]; print ENVIRON["PATH"]}'

会输出HOME环境变量。

算数运算和运算符

awk支持+ - * / % ^运算,^是幂指数运算,其余同C++。给出运算符的表:

python使用awk awk和python_数组_03


python使用awk awk和python_python使用awk_04

判断和循环

基本和C语言的一样。

if条件语句:

{
	if ( expression ) {
		statement; statement; ...
	} else if ( expression ) {
	
	} else {

	}
}

while循环

{
	while (condition) {
		statement;
	}
}

for循环

{
	for (x = 0; x < 4; x++) {
		print "iteration", x
	}
}

breakcontinue语句和C语言一致,不在赘述。

多条记录

awk规定,对于文本文件来说,默认的一条记录就是一行。

多行记录表示把默认的一行记录改成多行。举个例子,假设有一份名单,格式如下:

Tom
Google
New York

XiaoMing
Baidu
Beijing

分别是姓名、公司和地址为连着的三行,我们需要把这三行作为一个记录来处理。那么方式为:

BEGIN {
	FS="\n"
	RS=""
}
{
	print $1 ", " $2 ", " $3
}

FS表示把\n作为分隔符号,""表示把空行作为一个记录的分隔。

输出记录分隔符
上述代码中,", "可以进行简化替换,格式如下:

BEGIN {
	FS="\n"
	RS=""
	OFS=", "
}
{
	print $1, $2, $3
}

自定义函数

函数支持递归调用

awk的函数支持参数输入、返回数值。函数可以定义在程序顶层的任意位置,一般格式为:

function name(arg1, arg2, ..., argn) {
	statement(s)
}

指定的参数会当做局部变量,它们会隐藏同名的上一层变量。

函数分为传值和传递引用操作。awk不支持地址操作,传递引用只能靠数组实现。return作为返回值,如果不显式地返回,那么会返回0或者空字符串。所有函数内部未出现在参数列表中的变量,awk会把它们视为全局变量。

awk允许函数调用函数的参数少于函数定义中的参数,这样额外的参数会被视为局部变量。一般这类参数前面会添加额外的空白,这个额外的参数就像awk里面其他的变量一样,在函数内容中会被初始化为空字符串。

一个重要的作用是作为存储临时数值:

function add(x, y,   sum)
{
    sum = x + y;
    return sum;
}

{
    m = 2
    n = 3
    x = add(m, n)
    printf("sum = %d\n", sum);    
}

如果涉及到引用传递,那么必须封装到数组当中进行传递:

function swap(array,   temp) 
{
	temp = arry[1]
	array[1] = array[2]
	array[2] = temp
}

{
	array[1] = 2
	array[2] = 10
	swap(array)
}

字符串与算数处理

awk支持printf函数,用法和C语言完全一样。其有很多字符串处理函数,给出一个内置函数表:

python使用awk awk和python_AWK_05


同时,awk支持算数函数:

python使用awk awk和python_LinuxShell_06


python使用awk awk和python_分隔符_07