linux最常用命令awk详解
awk 是一种编程语言,用于在 linux/unix 下对文本和数据进行处理。数据可以来自标准输入 (stdin)、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是 linux/unix 下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk 有很多内建的功能,比如数组、函数等,这是它和 C 语言的相同之处,灵活性是 awk 最大的优势。
一. awk命令格式
语法形式
awk [options] 'script' file1
awk [options] -f scriptfile file1 file2
注:scriptfile
文件的内容为单引号中的内容即可
二. 常用命令选项
-F
指定输入分隔符,可以是字符串或正则表达式,如-F:
-v var=value
赋值一个用户定义变量,将外部变量传递给 awk(每定义一个变量一个参数 -v )-f scriptfile
从脚本文件中读取awk命令-v OFS="\t"
OFS 变量表示输出分隔符(每定义一个变量一个参数 -v )
三. awk模式和操作
awk脚本是由 模式 和 操作 来组成的。
模式可以是以下任意一个:
- /正则表达式/:使用通配符的扩展集,在"/" "/"这两根斜线之间的是正则表达式。
- 关系表达式:使用运算符进行操作,可以是字符串或数字的比较测试。
- 模式匹配表达式:用运算符 (匹配) 和 !(不匹配)。
- BEGIN 语句块、pattern 语句块、END 语句块。
操作由一个或多个命令、函数、表达式组成,之间由换行符或分号隔开,并位于大括号内,主要部分是:
- 变量或数组赋值
- 输出命令
- 内置函数
- 控制流语句
四. awk脚本基本结构
awk 'BEGIN{ print "start" } pattern{ commands } END{ print "end" }' file
# echo | awk 'BEGIN{ print "start" } { print "commands" } END{ print "end" }'
一个awk脚本通常由:BEGIN语句块、能够使用模式匹配的通用语句块、END语句块 3 部分组成,这三个部分是可选的。任意一个部分都可以不出现在脚本中,脚本通常是被单引号或双引号中,例如:
awk 'BEGIN{ i=0 } { i++ } END{ print i }' filename
awk "BEGIN{ i=0 } { i++ } END{ print i }" filename
五. awk的工作原理
awk 'BEGIN{ commands } pattern{ commands } END{ commands }'
第一步:执行 BEGIN{ commands }
语句块中的语句;
第二步:从文件或标准输入 (stdin) 读取一行,然后执行 pattern{ commands }
语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
第三步:当读至输入流末尾时,执行 END{ commands }
语句块。
- BEGIN 语句块在 awk 开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中。
- END 语句块在 awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在 END 语句块中完成,它也是一个可选语句块。
- pattern 语句块中的通用命令是最重要的部分,它也是可选的。如果没有提供pattern 语句块,则默认执行 { print },即打印每一个读取到的行,awk 读取的每一行都会执行该语句块。
六. awk内置变量
说明:[A][N][P][G]
表示第一个支持变量的工具,[A]=awk、[N]=nawk、[P]=POSIXawk、[G]=gawk
$n 当前记录的第n个字段,比如n为1表示第一个字段,n为2表示第二个字段。
$0 这个变量包含执行过程中当前行的文本内容。
[N] ARGC 命令行参数的数目。
[G] ARGIND 命令行中当前文件的位置(从1开始算)。
[N] ARGV 包含命令行参数的数组。
[G] CONVFMT 数字转换格式(默认值为%.6g)。
[P] ENVIRON 环境变量关联数组。
[N] ERRNO 最后一个系统错误的描述。
[G] FIELDWIDTHS 字段宽度列表(用空格键分隔)。
[A] FILENAME 当前输入文件的名。
[P] FNR 同NR,但相对于当前文件。
[A] FS 字段分隔符(默认是任何空格)。
[G] IGNORECASE 如果为真,则进行忽略大小写的匹配。
[A] NF 表示字段数,在执行过程中对应于当前的字段数。
[A] NR 表示记录数,在执行过程中对应于当前的行号。
[A] OFMT 数字的输出格式(默认值是%.6g)。
[A] OFS 输出字段分隔符(默认值是一个空格)。
[A] ORS 输出记录分隔符(默认值是一个换行符)。
[A] RS 记录分隔符(默认是一个换行符)。
[N] RSTART 由match函数所匹配的字符串的第一个位置。
[N] RLENGTH 由match函数所匹配的字符串的长度。
[N] SUBSEP 数组下标分隔符(默认值是34)。
- 使用
print $NF
可以打印出一行中的最后一个字段,使用$(NF-1)
则是打印倒数第二个字段,其他以此类推,打印每一行的第二和第三个字段,同时可以格式化打印字符串:
awk '{ print $2,$3 }' filename
awk '{ printf("%s^%s\n",$2,$3) }' filename
- 统计文件中的行数:下面命令只用了END语句块,在读入每一行的时,awk会将NR更新为对应的行号,当到达最后一行NR的值就是最后一行的行号,所以END语句块中的NR就是文件的行数。
awk 'END{ print NR }' filename
- 一个每一行中第一个字段值累加的例子:
seq 100 | awk 'BEGIN{sum=0} {sum+=$1} END{print "总和:"sum}'
总和:5050
七. awk输入输出
处理下一条记录
- awk中next语句,相当于其他编程语言的
continue
。在循环逐行匹配,如果遇到next,就会跳过当前行,然后直接进行下一行匹配。
awk '{if($1=="total"){next};print }' filename
- 分析发现需要将包含有 web 行进行跳过,然后需要将内容与下面行合并为一行:
# awk '/^web/{T=$0;next;}{print T":"$0;}' test.txt
简单地读取一条记录
- 执行 linux 的 date命令,并通过管道输出给getline,然后再把输出赋值给自定义变量out,并打印它:
awk 'BEGIN{ "date" | getline out; print out }' test
- 执行shell的date命令,并通过管道输出给getline,然后getline从管道中读取并将输入赋值给out,split函数把变量out转化成数组mon,然后打印数组mon的第二个元素:
awk 'BEGIN{ "date" | getline out; split(out,mon); print mon[2] }' test
- 命令ls的输出传递给geline作为输入,循环使getline从ls的输出中读取一行,并把它打印到屏幕。这里没有输入文件,因为BEGIN块在打开输入文件前执行,所以可以忽略输入文件。
awk 'BEGIN{ while( "ls" | getline) print }'
输出到一个文件 输出重定向
awk中允许用如下方式将结果输出到一个文件:
echo | awk '{printf("hello word!") > "datafile"}'
或
echo | awk '{printf("hello word!") >> "datafile"}'
设置字段定界符
- 默认的字段定界符是空格,可以使用-F "定界符" 明确指定一个定界符:
awk -F: '{ print $NF }' /etc/passwd
或
awk 'BEGIN{ FS=":" } { print $NF }' /etc/passwd
- 在BEGIN语句块中则可以用OFS=“定界符”设置输出字段的定界符。
awk 'BEGIN{FS=":"; OFS="-->"} {print $1,$3}' /etc/passwd
八. awk之空语句
某些地方需要一个占位符号,不需要执行任何语句,所以有了空语句。
单独一个分号;
表示一个空语句. 相当于Python的pass
,shell 的: