Linux命令awk的使用技巧
什么是awk
awk是一种处理文本文件的语言,是一个强大的文本分析工具。它可以对文本进行分割、过滤、格式化、计算等操作,还支持用户自定义函数和动态正则表达式等先进功能。awk可以在命令行中使用,也可以作为脚本来使用。
awk的基本语法
awk的基本语法如下:
awk [选项参数] 'script' var=value file(s)
或
awk [选项参数] -f scriptfile var=value file(s)
其中,选项参数可以是以下之一:
-F fs
或--field-separator fs
:指定输入文件的字段分隔符,fs是一个字符串或者是一个正则表达式,如-F:
。-v var=value
或--assign var=value
:赋值一个用户定义变量。-f scripfile
或--file scriptfile
:从脚本文件中读取awk命令。-mf nnn
和-mr nnn
:对nnn值设置内在限制,-mf
选项限制分配给nnn的最大块数目;-mr
选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适用。-W compact
或--compat
,-W traditional
或--traditional
:在兼容模式下运行awk。所以gawk的行为和标准的awk完全一样,所有的awk扩展都被忽略。-W copyleft
或--copyleft
,-W copyright
或--copyright
:打印简短的版权信息。-W help
或--help
,-W usage
或--usage
:打印全部awk选项和每个选项的简短说明。-W lint
或--lint
:打印不能向传统unix平台移植的结构的警告。-W lint-old
或--lint-old
:打印关于不能向传统unix平台移植的结构的警告。-W posix
:打开兼容模式。但有以下限制,不识别:\x
、函数关键字func
、换码序列以及当fs是一个空格时,将新行作为一个字段分隔符;操作符**
和**=
不能代替^
和^=
;fflush
无效。-W re-interval
或--re-interval
:允许间隔正则表达式的使用,参考 (grep中的Posix字符类),如括号表达式[[:alpha:]]
。-W source program-text
或--source program-text
:使用program-text作为源代码,可与-f
命令混用。-W version
或--version
:打印bug报告信息的版本。
script是包含一系列命令的awk脚本,通常有以下形式:
pattern { action }
pattern { action }
...
其中,pattern是一个匹配条件,可以是正则表达式、关系表达式、逻辑表达式或者特殊模式BEGIN
和END
。action是一个或多个命令,用花括号括起来,命令之间用分号分隔。如果省略pattern,则对所有的输入行执行action;如果省略action,则打印所有匹配pattern的行。
var=value是用户定义的变量,可以在script中使用,也可以在命令行中赋值。
file(s)是输入文件,可以有多个,用空格分隔。如果没有指定输入文件,则从标准输入读取数据。
awk的内置变量
awk有一些内置的变量,用来存储输入、输出和处理过程中的信息。常用的内置变量如下:
$n
:当前记录的第n个字段,字段间由FS
分隔。$0
表示完整的输入记录。ARGC
:命令行参数的数目。ARGIND
:命令行中当前文件的位置 (从0开始算)。ARGV
:包含命令行参数的数组。CONVFMT
:数字转换格式 (默认值为%.6g
)。ENVIRON
:环境变量关联数组。ERRNO
:最后一个系统错误的描述。FIELDWIDTHS
:字段宽度列表,用空格分隔。FILENAME
:当前输入文件的名字。FNR
:当前文件的记录数。FS
:输入字段分隔符 (默认是空格或Tab)。IGNORECASE
:如果为真,则进行忽略大小写的匹配。NF
:当前记录中的字段数。NR
:从开始至今读的记录数。OFMT
:数字的输出格式 (默认值是%.6g
)。OFS
:输出字段分隔符 (默认值是一个空格)。ORS
:输出记录分隔符 (默认值是一个换行符)。RS
:输入记录分隔符 (默认是一个换行符)。RSTART
:最近匹配的字符串的第一个位置。RLENGTH
:最近匹配的字符串的长度。SUBSEP
:数组下标分隔符 (默认值是\034
)。
awk的基本用法
1. 打印整个或部分记录
如果没有提供pattern和action,awk会打印整个输入记录,相当于指定了{ print $0 }
作为action。例如:
$ cat test.txt
Tom 20 male
Mary 18 female
Jack 22 male
$ awk '{ print $0 }' test.txt
Tom 20 male
Mary 18 female
Jack 22 male
如果只想打印部分字段,可以指定字段编号,如$1
表示第一个字段,$NF
表示最后一个字段。例如:
$ awk '{ print $1 }' test.txt
Tom
Mary
Jack
$ awk '{ print $1, $NF }' test.txt
Tom male
Mary female
Jack male
如果想改变输出字段的顺序或格式,可以使用printf
函数,它可以指定格式化字符串和对应的变量。例如:
$ awk '{ printf "%s is a %d years old %s\n", $1, $2, $3 }' test.txt
Tom is a 20 years old male
Mary is a 18 years old female
Jack is a 22 years old male
如果想改变输出字段的分隔符,可以设置OFS
变量,它的默认值是一个空格。例如:
$ awk 'BEGIN { OFS = "," } { print $1, $2, $3 }' test.txt
Tom,20,male
Mary,18,female
Jack,22,male
如果想在输出的每行前后加上一些内容,可以在print
或printf
前后加上字符串,用逗号分隔。例如:
$ awk '{ print "Name:", $1, "Gender:", $3 }' test.txt
Name: Tom Gender: male
Name: Mary Gender: female
Name: Jack Gender: male
2.假设有一个文件mail-list.txt,内容如下:
Amelia 555-5553 amelia.zodiacusque@gmail.com F
Anthony 555-3412 anthony.asserturo@hotmail.com A
Becky 555-7685 becky.algebrarum@gmail.com A
Bill 555-1675 bill.drowning@hotmail.com A
Broderick 555-0542 broderick.aliquotiens@yahoo.com R
Camilla 555-2912 camilla.infusarum@skynet.be R
Fabius 555-1234 fabius.undevicesimus@ucb.edu F
Julie 555-6699 julie.perscrutabor@skeeve.com F
Martin 555-6480 martin.codicibus@hotmail.com A
Samuel 555-3430 samuel.lanceolis@shu.edu A
Jean-Paul 555-2127 jeanpaul.campanorum@nyu.edu R
- 打印文件中的所有行:
awk '{print}' mail-list.txt
- 打印文件中第一列的内容:
awk '{print $1}' mail-list.txt
- 打印文件中第二列和第三列的内容,用逗号分隔:
awk '{print $2, $3}' OFS=',' mail-list.txt
- 打印文件中最后一列为F的行:
awk '$NF=="F" {print}' mail-list.txt
- 打印文件中包含gmail的行:
awk '/gmail/ {print}' mail-list.txt
- 打印文件中每行的列数:
awk '{print NF}' mail-list.txt
- 打印文件中的总行数:
awk 'END {print NR}' mail-list.txt
- 打印文件中第一列的最长字符串:
awk 'length($1) > max {max = length($1); name = $1} END {print name}' mail-list.txt
- 打印文件中第二列的电话号码的平均值:
awk '{sum += $2} END {print sum/NR}' mail-list.txt
- 使用冒号:作为分隔符,打印文件中第三列的域名:
awk -F '@' '{print $2}' mail-list.txt