已复制
全屏展示
复制代码

linux最常用命令awk详解


· 7 min read

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 的:

🔗

文章推荐