Linux shell:awk命令使用详解

1、简介

awk与grep、sed命令一样都是以行为单位读取文本的,默认以空格或Tab键为分隔符,将分割所得的各个字段保存到内建变量中供后续使用。

命令格式:

awk [选项] '命令' 文件名

选项说明:

  • -F fs or --field-separator fs:相当于内建变量“FS”,指定分割符为fs,默认为空格或Tab制表符;
  • -f scripfile or --file scriptfile:从文件中读取awk指令,用来代替命令行中输入的命令;
  • -v var=value or --asign var=value:设置一个变量并且附上初值。

字段变量:

  • $0:整个文本行
  • $1:文本行中第1个数据字段
  • $2:文本行中第2个数据字段
  • $n:文本行中第n个数据字段

2、基本用法

普通输出内容:

linrm@linrm-VirtualBox:~$ cat file1.txt
i am a test file!
thank you!
r u ok?
year, month, day, hour, minute, second
linrm@linrm-VirtualBox:~$ awk '{print $1,$4}' file1.txt # 普通输出
i test
thank
r
year, hour,
linrm@linrm-VirtualBox:~$ awk '{printf "%-8s %-10s\n",$1,$4}' file1.txt # 格式化输出
i        test
thank
r
year,    hour,

指定“,”为分割符:

linrm@linrm-VirtualBox:~$ awk -F, '{print $1,$4}' file1.txt
i am a test file!
thank you!
r u ok?
year  hour

指定多个分割符输出(首先使用空格,然后在使用其他分割符):

linrm@linrm-VirtualBox:~$ awk -F '[, ]' '{print $1,$2,$4}' file1.txt
i am test
thank you!
r u
year

从文件中读取awk指令:

linrm@linrm-VirtualBox:~$ cat file.awk
{print $1,$4}
linrm@linrm-VirtualBox:~$ awk -f file.awk file1.txt
i test
thank
r
year, hour,

设置变量:

linrm@linrm-VirtualBox:~$ cat file2.txt
101 i am a test file!
102 thank you!
103 r u ok?
104 year, month, day, hour, minute, second
linrm@linrm-VirtualBox:~$ awk -va=1 -vb=sss '{print $1,$1+a,$1a,$1b}' file2.txt
101 102 1011 101sss
102 103 1021 102sss
103 104 1031 103sss
104 105 1041 104sss

3、运算符

运算符描述
= += -= *= /= %= ^= **=赋值
?:C语言三目运算符
< <= > >= != ==关系运算
+ - * / %运算
^ **求幂
++ –自增自减
||和&&逻辑或/与
和!匹配正则表达式与否
空格连接
$字段引用
in数组成员

过滤第一列大于102的行:

linrm@linrm-VirtualBox:~$ cat file2.txt
101 i am a test file!
102 thank you!
103 r u ok?
104 year, month, day, hour, minute, second
linrm@linrm-VirtualBox:~$ awk '$1>102' file2.txt
103 r u ok?
104 year, month, day, hour, minute, second

过滤第一列大于101并且第二列等于thank的行:

linrm@linrm-VirtualBox:~$ awk '$1 > 101 && $2 == "thank" {print $1,$2,$3}' file2.txt
102 thank you!

4、BEGIN/END关键字

这两个关键字的作用是指定脚本命令的运行时机,默认情况下awk是从输入中读取一行字符串,然后对该行执行相应的命令,而有时候想在执行这些命令之前先进行一些其他的脚本命令,则可以使用BEGIN关键字,而END关键字的处理时机则刚好相反。

linrm@linrm-VirtualBox:~$ awk 'BEGIN{print "---file start---"} {print $1,$4} END{print "---file end---"}' file2.txt
---file start---
101 a
102
103 ok?
104 day,
---file end---

5、内建变量

内建变量说明
$0完整的输入记录
$1 $2 $n第1、2、n个字段
FS字段分割符
ARGC命令行参数个数
ARGV命令行参数数组
ARGIND命令行中当前文件的位置(从0开始算)
FILENAME当前文件名
IGNORECASE是否忽略大小写
ERRNO最后一个系统错误的描述
CONVFMT转换格式(默认为%.6g)
FIELDWIDTHS字符宽度列表
FNR各文件分别计数的行号
NF一条记录的字段的数目
NR已经读出的字段的数目
OFMT数字的输出格式(默认为%.6g)
OFS输出字段分隔符
ORS输出记录分隔符
RLENGTH由match函数所匹配的字符串长度
RS记录分隔符
RSTART由match函数所匹配的第一个位置
SUBSEP数组下标分隔符

输出时以“ - ”符进行分隔:

linrm@linrm-VirtualBox:~$ awk '{print $1, $2, $3}' OFS=" - " file2.txt
101 - i - am
102 - thank - you!
103 - r - u
104 - year, - month,

查看每一行的字段数:

linrm@linrm-VirtualBox:~$ awk '{print "NF = " NF}' file2.txt # 或:awk '{printf "NF = %s\n", NF}' file2.txt
NF = 6
NF = 3
NF = 4
NF = 7

忽略大小写(网上是这么写的,但我试了下好像不行,难道哪里出错了?):

linrm@linrm-VirtualBox:~$ awk 'BEGIN{IGNORECASE=1} /thank/ {print $1, $2, $3}' file2.txt

6、支持正则表达式

输出包含字符串“ou”的行:

linrm@linrm-VirtualBox:~$ awk '/ou/' file2.txt 	# 输出包含"ou"的行
102 thank you!
104 year, month, day, hour, minute, second
linrm@linrm-VirtualBox:~$ awk '!/ou/' file2.txt # 输出不包含"ou"的行
101 i am a test file!
103 r u ok?

输出第2列包含字符“i”的行的第1、2、3列:

linrm@linrm-VirtualBox:~$ awk '$2 ~ /i/ {print $1, $2, $3}' file2.txt 	# ~表示匹配正则表达式
101 i am
linrm@linrm-VirtualBox:~$ awk '$2 !~ /i/ {print $1, $2, $3}' file2.txt 	# !~表示不匹配正则表达式
102 thank you!
103 r u
104 year, month,

7、字符串函数

函数说明
length()返回字符串的长度
index()返回下标
tolower()转换成小写并返回字符串
toupper()转换成大写并返回字符串
substr()返回字符串中的子串
match()返回下标,但它不搜索子串
sub()替换匹配的第一个字符串序列,并返回整个字符串
gsub()替换匹配的所有字符串序列,并返回整个字符串
split()分割字符串并将各部分放到使用整数下标的数组中

打印各行字符串的长度:

linrm@linrm-VirtualBox:~$ awk '{print length()}' file2.txt # 这里的“()”可省略
21
14
11
42

打印字符串长度超过20的行:

linrm@linrm-VirtualBox:~$ awk 'length>20' file2.txt
101 i am a test file!
104 year, month, day, hour, minute, second

字符串大小写转换:

linrm@linrm-VirtualBox:~$ awk '{print $1, tolower($2), toupper($3)}' file2.txt
101 i AM
102 thank YOU!
103 r U
104 year, MONTH,

8、其他示例

打印9x9乘法表:

seq 9 | sed 'H;g' | awk -v RS='' '{for(i=1;i<=NF;i++)printf("%dx%d=%d%s", i, NR, i*NR, i==NR?"\n":"\t")}'

参考文章:


版权声明:本文为weixin_44498318原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。