awk命令

​awk是一个强大的文本处理工具。
awk把文件逐行的读入,一行叫一条记录,以空格为分隔符将每行切片,切开的部分叫域或者列或者字段,然后处理各个字段。

awk有3个不同版本:awk、nawk、gawk。
未作特别说明,一般指gawk,gawk是AWK的GNU版本。

awk其名称源自它的创始人Alfred Aho 、Peter Weinberger和Brian Kernighan姓氏的首个字母。

一、调用awk的方法

1.命令行方式

awk [options] 'commands' input-file(s)

2.脚本方式


将所有的awk命令写入一个文件,并使其可执行,然后将awk命令解释器作为脚本的首行,通过键入脚本名称来调用。

相当于shell脚本首行的#!/bin/sh换成#!/bin/awk

二、命令行方式用法

(一)语法格式

用法:awk [选项] -f 脚本文件 [--] 文件...
用法:awk [选项] [--] '程序' 文件...

(二)选项

-f 脚本文件, --file=脚本文件
-F fs, --field-separator=fs
-v var=val, --assign=var=val
-b, --characters-as-bytes
-c, --traditional
-C, --copyright
-d[文件], --dump-variables[=文件]
-D[文件], --debug[=文件]
-e '程序文本', --source='程序文本'
-E 文件, --exec=文件
-g, --gen-pot
-h, --help
-i 包含文件, --include=包含文件
-I, --trace
-l 库, --load=库
-L[fatal|invalid|no-ext], --lint[=fatal|invalid|no-ext]
-M, --bignum
-N, --use-lc-numeric
-n, --non-decimal-data
-o[文件], --pretty-print[=文件]
-O, --optimize
-p[文件], --profile[=文件]
-P, --posix
-r, --re-interval
-s, --no-optimize
-S, --sandbox
-t, --lint-old
-V, --version

(三)参数


1.程序


也叫脚本命令
格式为:

'模式{操作}'

它由两部分组成,分别为模式和操作。模式也可以叫做条件或者地址。

整个脚本命令是用单引号’'括起。为了防止shell解析特殊字符。

如果是执行多条脚本命令,格式为:

'模式1{命令1};模式2{命令2}...'
(1)模式


用来指定要处理的行。
模式可以是以下任意一个:

/正则表达式/:使用ERE。
关系表达式:使用运算符操作,可以是字符串或数字的比较测试。
包含表达式:使用运算符~(包含)和!~(不包含)。
BEGIN:如果模式是BEGIN,说明后面的操作只在程序开始时执行一次。
END:如果模式是END,说明后面的操作只在程序结束时执行一次。
模式1, 模式2:从匹配模式1的行到匹配模式2的行(包含该行)。
省略:表示处理所有行。
条件类型条 件说 明
awk保留字BEGIN在 awk 程序一开始,尚未读取任何数据之前执行。BEGIN 后的动作只在程序开始时执行一次
awk保留字END在 awk 程序处理完所有数据,即将结束时执行。END 后的动作只在程序结束时执行一次
关系运算符>大于
<小于
>=大于等于
<=小于等于
==等于。用于判断两个值是否相等
!=不等于
A~B判断字符串 A 中是否包含能匹配 B 表达式的子字符串
A!~B判断字符串 A 中是否不包含能匹配 B 表达式的子字符串
正则表达式/正则/匹配正则表达式的行

例如:

x>10:判断变量 x 是否大于10;
x == y:判断变量 x 是否等于变量 y;
A~B:判断字符串 A 中是否包含能匹配 B 表达式的子字符串;
A!~B:判断字符串 A 中是否不包含能匹配 B 表达式的子字符串;
(2)操作


操作由一个或多个命令、函数、表达式组成,之间由换行符或分号隔开,并位于大括号内,大括号不是必须的。

主要部分是:
变量或数组赋值
输入输出
内置函数
控制流语句

2.一个或多个文件

(四)内置变量

变量描述
$n当前记录的第n个字段,字段间由FS分隔,n从1开始
$0完整的输入记录
ARGC命令行参数的数目
ARGIND命令行中当前文件的位置(从0开始算)
ARGV包含命令行参数的数组
CONVFMT数字转换格式(默认值为%.6g)ENVIRON环境变量关联数组
ERRNO最后一个系统错误的描述
FIELDWIDTHS字段宽度列表(用空格键分隔)
FILENAME当前文件名
FNR各文件分别计数的行号
FS字段分隔符(默认是任何空格)
IGNORECASE如果为真,则进行忽略大小写的匹配
NF一条记录的字段的数目
NR已经读出的记录数,就是行号,从1开始
OFMT数字的输出格式(默认值是%.6g)
OFS输出字段分隔符,默认值与输入字段分隔符一致。
ORS输出记录分隔符(默认值是一个换行符)
RLENGTH由match函数所匹配的字符串的长度
RS记录分隔符(默认是一个换行符)
RSTART由match函数所匹配的字符串的第一个位置
SUBSEP数组下标分隔符(默认值是/034)

(五)示例用法


1.使用内置函数


最常用的内置函数就是输出函数。awk中同时提供了print和printf两种打印输出的函数。

(1)print


是默认命令。
print函数的参数可以是变量、数值、字符串。字符串必须用双引号引用,参数用逗号分隔。如果没有逗号,参数就串联在一起而无法区分。

print函数的输出会把各参数用空格分开。print函数默认会在每行后面加上ORS。

如,

'{print key, "=" value}'
(2)printf


printf函数,其用法和c语言中printf基本相似,可以格式化字符串,输出复杂时,printf更加好用,代码更易懂。需要特别注意的是使用printf时默认是不会换行的,需要手动加\n。

printf 语句的格式如下:

printf(format, value1, value2, ..., valuen)

其中format是格式字符串,包含要原样打印的文本和规格(specification)。

一个规格是一个%符后面跟着一些字符,用来控制一个 value的格式。
第一个规格说明如何打印value1,第二个说明如何打印value2,依次类推。因此,有多少value要打印,在format中就要有多少个规格。

规格说明
%d十进制有符号整数
%u十进制无符号整数
%f浮点数
%s字符串
%c单个字符
%p指针的值
%e指数形式的浮点数
%x无符号以十六进制表示的整数
%o无符号以八进制表示的整数
%g自动选择合适的表示法

如,

'{ printf("total pay for %s is $%.2f\n", $1, $2 * $3) }'
输出样例:
total pay for Beth is $0.00
total pay for Dan is $0.00
total pay for Kathy is $40.00
total pay for Mark is $100.00
total pay for Mary is $121.00
total pay for Susie is $76.50

第一个规格是%s,说明以字符串的方式打印第一个值 $1。
第二个是%.2f,说明以数字的方式打印第二个值$2*$3,并保留小数点后面两位。
规格字符串中其他东西,包括美元符号,原样打印。
字符串尾部的\n代表开始新的一行,使得后续输出将从下一行开始。

'{ printf("%-8s $%6.2f\n", $1, $2 * $3) }'
Beth     $  0.00
Dan      $  0.00
Kathy    $ 40.00
Mark     $100.00
Mary     $121.00
Susie    $ 76.50

第一个规格%-8s将一个姓名以字符串形式在8个字符宽度的字段中左对齐输出。
第二个规格%6.2f将薪酬以数字的形式,保留小数点后两位,在6个字符宽度的字段中输出。

(3)length函数

length([string])返回字符串的长度。比如:length("abc")返回3

length()返回$0的长度。

 从文件中找出长度大于 80 的行:

awk 'length()>80' log.txt

2.使用外部命令


(1)使用system函数执行外部命令


①语法格式

awk '{system("command")}' file

system的返回值是command执行的返回值
command必须使用双引号引起来。

②示例

awk 'BEGIN{system("ls")}' file.txt
(2)使用管道


awk中的管道概念和shell的管道类似,都是使用"|"符号。如果在awk程序中打开了管道,必须先关闭该管道才能打开另一个管道。也就是说一次只能打开一个管道。管道一旦打开,就会保持打开状态直至awk退出。

又分为两种:
一种是配合getline
一种是配合print

①配合getline
1)格式

awk '{"command" | getline [var]}' file

var是可选参数,用于存储命令执行后的标准输出,默认情况下结果输出到$0
command必须用双引号引起来。

执行的结果缓存于pipe中,再传送给awk处理,如果有多行数据,awk的getline命令可能调用多次。

2)示例

awk '{"curl www.baidu.com" | getline result; print(result);}' file.txt

$awk 'BEGIN{ while(("ls" | getline d) > 0) print d}' file.txt

②配合print或printf
1)格式

awk '{print ... | "command"}' file

command必须用双引号引用起来。
output是先缓存在pipe中,等输出完毕后再调用shell命令处理,shell命令只处理一次,而且处理的时机是“awk程序结束时,或者管道关闭时(需要显式的关闭管道)”

2)示例

$ awk 'BEGIN{print "foobar" | "echo eew"}' file.txt 
eew

$ awk 'BEGIN{count=0} /west/{count++} {printf("%s %stt%-15sn", $3,$4,$1) | "sort +1"} END{close("sort +1"); printf("The number of sales pers in the western"); print "region is " count "."}' file.txt

printf函数用于将输出格式化并发送给管道。所有输出集齐后一同发送给sort命令。
必须用与打开时完全相同的命令来关闭管道(sort +1),否则END块中的语句将与前面的输出一起被排序。
此处的sort命令只执行一次。

awk调用外部命令都是新开一个shell,所以要注意当前shell变量与新开shell变量问题

root@ubuntu:~# abc=12345567890
root@ubuntu:~# awk 'BEGIN{system("echo $abc")}'
root@ubuntu:~#
root@ubuntu:~# export abc=12345567890
root@ubuntu:~# awk 'BEGIN{system("echo $abc")}'
12345567890
root@ubuntu:~#
root@ubuntu:~# abc=1234567890
root@ubuntu:~# awk 'BEGIN{print "echo","$abc"| "/bin/bash"}'
root@ubuntu:~#
root@ubuntu:~# export abc=1234567890
root@ubuntu:~# awk 'BEGIN{print "echo","$abc"| "/bin/bash"}'
1234567890
root@ubuntu:~#

3.使用内置变量


(1)变量NF


表示当前行有多少个字段,字段从1开始编号。

$NF就代表最后一个字段。

$ echo 'this is a test' | awk '{print $NF}'
test

$(NF-1)代表倒数第二个字段。

$ awk -F ':' '{print $1, $(NF-1)}' demo.txt
root /root
daemon /usr/sbin
bin /bin
sys /dev
sync /bin
(2)删除列


比如,删除第2列,让它等于空

awk '{$2 = ""; print $0}' file
awk '{$2 = null; print $0}' file

但是这种写法会多出一个空格,如下例:

[root@centos79 test3]# cat a.txt
3 5 6 2
s g 3 5
c f h e
[root@centos79 test3]# awk '{$2 = ""; print $0}' a.txt
3  6 2
s  3 5
c  h e

删除第二列,不留空格的写法如下

awk '{$2 = "\b"; print $0}' file

如下例:

[root@centos79 test3]# cat a.txt
3 5 6 2
s g 3 5
c f h e
[root@centos79 test3]# awk '{$2 = "\b"; print $0}' a.txt
3 6 2
s 3 5
c h e
(3)统计/etc/passwd文件名,每行的行号,每行的列数

#awk -F':' '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF}' /etc/passwd
filename:/etc/passwd,linenumber:1,columns:7
filename:/etc/passwd,linenumber:2,columns:7
filename:/etc/passwd,linenumber:3,columns:7
filename:/etc/passwd,linenumber:4,columns:7
(4)使用自定义变量

awk中自定义变量不需要声明,默认初始值是0,所以不用初始化,可以直接使用。

例子:计算文件大小

$ ls -l *.txt | awk '{sum+=$5} END {print sum}'
666581

4.直接使用shell变量。


(1)是“双引号+单引号+shell变量+单引号+双引号”的格式
awk '{print "'$shellvar'"}' filename
$ foo=bar
$ awk 'BEGIN{print "'$foo'"}' file.txt
bar
(2)是“双引号+单引号+双引号+shell变量+双引号+单引号+双引号”的格式
awk '{print "'"$shellvar"'"}' filename

如果变量的值中包含空格,为了shell不把空格作为分隔符,则应使用这种方法

(3)export变量,然后在awk中使用ENVIRON[“var”]形式获取环境变量的值
awk '{print ENVIRON["var"]}' filename
$ export foo=bar
$ awk 'BEGIN{print  ENVIRON["foo"]}' file.txt
bar
(4)使用-v选项


定义变量时,让其值等于shell变量的值
示例:

foo=bar
awk -v awkfoo=$foo '{print awkfoo}' file.txt

实例:

 $ awk -va=1 '{print $1,$1+a}' log.txt
 ---------------------------------------------
 2 3
 3 4
 This's 1
 10 11
 $ awk -va=1 -vb=s '{print $1,$1+a,$1b}' log.txt
 ---------------------------------------------
 2 3 2s
 3 4 3s
 This's 1 This'ss
 10 11 10s

5.-F选项


默认情况下,awk会使用空格分割一行数据,但是可以使用-F选项指定分隔符。-F后面的分隔符可以用双引号,也可以用单引号,也可以不用引号。

Num,Name,Company,Product
1,Jobs,Apple,iPhone
2,Jack,Alibaba,taobao
3,Pony,Tencent,wechat

awk -F"," '{print $2"\t"$3}' form.txt
Name    Company
Jobs    Apple
Jack    Alibaba
Pony    Tencent

这里的选项 -F “,” 就表示以每行数据中的逗号为分隔符,来切分数据。

实例:

#使用","分割
 $  awk -F, '{print $1,$2}' log.txt
 2 this is a test
 3 Are you like awk
 This's a test
 10 There are orange apple
 
 # 或者使用内建变量
 $ awk 'BEGIN{FS=","} {print $1,$2}' log.txt
 2 this is a test
 3 Are you like awk
 This's a test
 10 There are orange apple
 
 # 使用多个分隔符
 $ awk -F '[ ,]'  '{print $1,$2,$5}'   log.txt
 2 this test
 3 Are awk
 This's a
 10 There apple

6.-f选项从文件中读取程序


awk 允许将脚本命令存储到文件中,然后再在命令行中引用,比如:
假设有这么一个文件(学生成绩表):

$ cat score.txt
Marry   2143 78 84 77
Jack    2321 66 78 45
Tom     2122 48 77 71
Mike    2537 87 97 95
Bob     2415 40 57 62

我们的 awk 脚本如下:

$ cat cal.awk
#!/bin/awk
#运行前
BEGIN {
    math = 0
    english = 0
    computer = 0
 
    printf "NAME    NO.   MATH  ENGLISH  COMPUTER   TOTAL\n"
    printf "---------------------------------------------\n"
}
#运行中
{
    math+=$3
    english+=$4
    computer+=$5
    printf "%-6s %-6s %4d %8d %8d %8d\n", $1, $2, $3,$4,$5, $3+$4+$5
}
#运行后
END {
    printf "---------------------------------------------\n"
    printf "  TOTAL:%10d %8d %8d \n", math, english, computer
    printf "AVERAGE:%10.2f %8.2f %8.2f\n", math/NR, english/NR, computer/NR​
}
我们来看一下执行结果:

$ awk -f cal.awk score.txt
NAME    NO.   MATH  ENGLISH  COMPUTER   TOTAL
---------------------------------------------
Marry  2143     78       84       77      239
Jack   2321     66       78       45      189
Tom    2122     48       77       71      196
Mike   2537     87       97       95      279
Bob    2415     40       57       62      159
---------------------------------------------
  TOTAL:       319      393      350
AVERAGE:     63.80    78.60    70.00

7.BEGIN END模式

awk 'BEGIN{ commands } pattern{ commands } END{ commands }'

第一步:执行BEGIN{ commands }语句块中的语句;
第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ commands }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
第三步:当读至输入流末尾时,执行END{ commands }语句块。

BEGIN语句块在awk开始从输入流中读取行之前执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中。

END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块。

pattern语句块中的通用命令是最重要的部分,它也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块。

示例

echo -e "A line 1\nA line 2" | awk 'BEGIN{ print "Start" } { print } END{ print "End" }'
Start
A line 1
A line 2
End

8.条件表达式模式


(1)下面用一个综合的例子来说明awk的条件判断和数值计算,有这样一组数据保存为pay.txt:
Name    1st   2nd   3rd
VBird   23000   24000  25000
DMTsai  21000   20000  23000
Bird2   43000   42000  41000

现在想加一列"Total",计算每一行的数值总和。

用awk可以完成这个需求:

awk 'NR==1 {printf "%10s %10s %10s %10s %10s \n",$1,$2,$3,$4,"Total"};NR>1 {printf "%10s %10s %10s %10s %10s \n",$1,$2,$3,$4,$2+$3+$4}' pay.txt
(2)过滤第一列大于2的行
$ awk '$1>2' log.txt
#输出
3 Are you like awk
This's a test
10 There are orange,apple,mongo
(3)过滤第一列等于2的行
$ awk '$1==2 {print $1,$3}' log.txt
#输出
2 is
(4)过滤第一列大于2并且第二列等于’Are’的行
$ awk '$1>2 && $2=="Are" {print $1,$2,$3}' log.txt
#输出
3 Are you

9.使用循环语句


(1)输出每行的前5列,并按行输出
awk '{for(i=1;i<6;i++)printf("%s ",$i);printf("\n")}' input.file
(2)输出多列,并更改分隔符为TAB
awk '{for(i=2;i<=NF;i++)printf("%s\t",$i);printf("\n")}' input.file
(3)每三行作为一列输出
awk '{if(NR%3 != 0){ORS="\t"}else{ORS="\n"}print}' input.file
(4)打印九九乘法表
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")}'
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值