### AWK 是一种处理文本文件的语言,是一个强大的文本分析工具。
awk [选项参数] 'script' var=value file(s)
或
awk [选项参数] -f scriptfile var=value file(s)
POSIX options: GNU long options: (standard)
-f progfile --file=progfile 从脚本文件中读取awk命令。
-F fs --field-separator=fs 指定输入文件折分隔符,fs是一个字符串或者是一个正则表达式,如-F:。
-v var=val --assign=var=val 赋值一个用户定义变量。
Short options: GNU long options: (extensions)
-b --characters-as-bytes
-c --traditional
-C --copyright
-d[file] --dump-variables[=file]
-D[file] --debug[=file]
-e 'program-text' --source='program-text'
-E file --exec=file
-g --gen-pot
-h --help
-i includefile --include=includefile
-l library --load=library
-L[fatal|invalid] --lint[=fatal|invalid]
-M --bignum
-N --use-lc-numeric
-n --non-decimal-data
-o[file] --pretty-print[=file]
-O --optimize
-p[file] --profile[=file]
-P --posix
-r --re-interval
-s --no-optimize
-S --sandbox
-t --lint-old
-V --version 打印bug报告信息的版本。
内置变量
$n 当前记录的第n个字段,字段间由FS分隔
$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)
运算符
= += -= *= /= %= ^= **= 赋值
?: C条件表达式
|| 逻辑或
&& 逻辑与
~ 和 !~ 匹配正则表达式和不匹配正则表达式
< <= > >= != == 关系运算符
空格 连接
+ - 加,减
* / % 乘,除与求余
+ - ! 一元加,减和逻辑非
^ *** 求幂
++ -- 增加或减少,作为前缀或后缀
$ 字段引用
in 数组成员
调用方法
1.命令行方式
awk [-F field-separator] 'commands' input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可选的。 input-file(s) 是待处理的文件。
在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。
2.shell脚本方式
将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。
相当于shell脚本首行的:#!/bin/sh
可以换成:#!/bin/awk
3.将所有的awk命令插入一个单独文件,然后调用:
awk -f awk-script-file input-file(s)
其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的。
实例
准备的内容
$ ps aux
PID PPID PGID WINPID TTY UID STIME COMMAND
1481 1480 1481 1956 pty0 197611 11:33:08 /usr/bin/bash
1967 1481 1967 9968 pty0 197611 17:19:56 /usr/bin/ps
1480 1 1480 1548 ? 197611 11:33:07 /usr/bin/mintty
基础实例
显示PPID列 $n 内建变量 FS默认是空格
$ ps aux | awk '{print $2}'
PPID
1481
1480
1
指定 分隔符 FS 为 ':' 也可以是正则表达式 也可以前面跟 -F 指定
$ ps aux | awk '{FS=":"} { print $0}'
PID PPID PGID WINPID TTY UID STIME COMMAND
1481 1480 1481 1956 pty0 197611 11:33:08 /usr/bin/bash
2051 1481 2050 22224 pty0 197611 17:26:47 /usr/bin/bash
2050 1481 2050 11672 pty0 197611 17:26:47 /usr/bin/ps
1480 1 1480 1548 ? 197611 11:33:07 /usr/bin/mintty
$ ps aux | awk '{FS=":"} { print $1}'
PID
1481 1480 1481 1956 pty0 197611 11
1480 1 1480 1548 ? 197611 11
2055 1481 2055 7996 pty0 197611 17
$ ps aux | awk '{FS=":"} { print $2}'
PPID
33
26
33
$ ps aux | awk '{FS=":"} { print $3}'
PGID
54 /usr/bin/ps
08 /usr/bin/bash
07 /usr/bin/mintty
$ ps aux | awk -F':' '{if(NR >2 ) print "结果是:"$3}'
结果是:47 /usr/bin/ps
结果是:07 /usr/bin/mintty
添加提示
$ ps aux | awk '{FS=":"} { print "结果是:"$3}'
结果是:PGID
结果是:08 /usr/bin/bash
结果是:40 /usr/bin/bash
结果是:40 /usr/bin/ps
结果是:07 /usr/bin/mintty
限制行数 显示 从第二行开始 使用内建变量 NR 假如是多文件就用 FNR(分文件计算行数)
$ ps aux | awk '{FS=":"} {if(NR > 2 ) print "结果是:"$3}'
结果是:08 /usr/bin/bash
结果是:41 /usr/bin/ps
结果是:07 /usr/bin/mintty
进阶实例(1)
准备的内容
> a.txt
1,a-1
2,a-2
3,a-3
4,a-4
> b.txt
2,b-2
4,b-4
5,b-5
$ ps aux | awk -F',' '{ print "结果是:" NR,FNR,$0}' a.txt b.txt
结果是:1 1 1,a-1
结果是:2 2 2,a-2
结果是:3 3 3,a-3
结果是:4 4 4,a-4
结果是:5 1 2,b-2
结果是:6 2 4,b-4
结果是:7 3 5,b-5
$ awk -F',' 'NR==FNR{a[$1]=$2;}NR!=FNR{print $0,a[$1]}' b.txt a.txt
1,a-1
2,a-2 b-2
3,a-3
4,a-4 b-4
解释:
a[] 是一个数组,在先读取 b.txt 文件的时候开始做一个暂存,当 NR==FNR时,并不会执行后面的 {print $0,a[$1]}
当 NR!=FNR 不会执行前面的 {a[$1]=$2;}
此时 a[] 数组存的是 b.txt 文件中 以 逗号 前面的值为索引 逗号后面的为 值
用 a文件中 逗号前面的值取数组中的值 并打印 a文件的行号。
总结
在这个实例中,我们共运用了 类似 if...else...的语句,也使用了 变量数组。
这个类似于 通过逗号前面的值 实现 a.txt left outer join b.txt
进阶实例(2)
准备内容
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 19360 1308 ? Ss 2019 0:41 /sbin/init
root 2 0.0 0.0 0 0 ? S 2019 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S 2019 0:25 [migration/0]
root 4 0.0 0.0 0 0 ? S 2019 0:43 [ksoftirqd/0]
root 5 0.0 0.0 0 0 ? S 2019 0:00 [stopper/0]
root 6 0.0 0.0 0 0 ? S 2019 0:14 [watchdog/0]
root 7 0.0 0.0 0 0 ? S 2019 0:25 [migration/1]
root 8 0.0 0.0 0 0 ? S 2019 0:00 [stopper/1]
root 9 0.0 0.0 0 0 ? S 2019 0:53 [ksoftirqd/1]
root 10 0.0 0.0 0 0 ? S 2019 0:11 [watchdog/1]
root 11 0.0 0.0 0 0 ? S 2019 0:23 [migration/2]
root 12 0.0 0.0 0 0 ? S 2019 0:00 [stopper/2]
pattern 使用示例 分隔符是 ‘00’
$ awk -F00 '/stopper/ {print $0}' x.txt
root 5 0.0 0.0 0 0 ? S 2019 0:00 [stopper/0]
root 8 0.0 0.0 0 0 ? S 2019 0:00 [stopper/1]
root 12 0.0 0.0 0 0 ? S 2019 0:00 [stopper/2]
$ awk -F00 '/stopper/ {print $1}' x.txt
root 5 0.0 0.0 0 0 ? S 2019 0:
root 8 0.0 0.0 0 0 ? S 2019 0:
root 12 0.0 0.0 0 0 ? S 2019 0:
$ awk -F00 '/stopper/ {print $2}' x.txt
[stopper/0]
[stopper/1]
[stopper/2]
print 与 printf
awk中同时提供了print和printf两种打印输出的函数。
其中print函数的参数可以是变量、数值或者字符串。字符串必须用双引号引用,参数用逗号分隔。如果没有逗号,参数就串联在一起而无法区分。这里,逗号的作用与输出文件的分隔符的作用是一样的,只是后者是空格而已。
printf函数,其用法和c语言中printf基本相似,可以格式化字符串,输出复杂时,printf更加好用,代码更易懂。
$ awk -F '00' '/stopper/ {printf "linenum: %s,content: %s \n" ,NR,$0}' x.txt
linenum: 6,content: root 5 0.0 0.0 0 0 ? S 2019 0:00 [stopper/0]
linenum: 9,content: root 8 0.0 0.0 0 0 ? S 2019 0:00 [stopper/1]
linenum: 13,content: root 12 0.0 0.0 0 0 ? S 2019 0:00 [stopper/2]
进阶实例(3)
行数计数 准备内容同上
$ awk 'BEGIN{count = 0;print count} {count++;} END{print count}' x.txt
0
13
条件语句
计算 PID > 5 的之和 准备内容同上
$ awk 'BEGIN {count = 0} {if($2>5){count=count+$2;}} END {print "pid sum is = "count}' x.txt
pid sum is = 63
match 函数
awk 'BEGIN{start=match("this is a test",/[a-z]+$/); print start, RSTART, RLENGTH }' x.txt
附录 常用字符串函数
…….