26.awk 使用手册
文章目录
- awk 使用手册
- awk 介绍
- awk 命令
- awk 命令格式
- awk 工作流
- awk 示例
- awk 综合示例
- 问题
- 分析
- 解答
- 表头
- 数据
- awk 命令选项
- --help 选项
- -F 选项
- awk 内置变量
- NF 变量
- NR 变量
awk 使用手册
awk 介绍
awk 是一个强大的文本分析工具。
awk 更像一门编程语言,他可以自定义变量,有条件语句,有循环,有数组,有正则,有函数等。
awk 按行读取数据,根据给出的条件进行查找,并在找出来的行中进行操作。
awk 有三种形势,awk,gawk,nawk,平时所说的awk其实就是gawk。
awk 是其取了三位创始人 Alfred Aho,Peter Weinberger, 和 Brian Kernighan 的 Family Name 的首字符。
使用 awk 可以完成无数的任务,我们简单的罗列几条:
- 文本处理
- 生成格式化的文本报告
- 运行一些简单的算术操作
- 执行一些常见的字符串操作
awk 命令
awk 命令格式
awk [options] 'script' file(s)
awk [options] -f scriptfile file(s)
script
,定义如何处理数据。file
,是 awk 处理的数据来源,awk 也可以来自其它命令的输出。-f scriptfile
从脚本文件中读取awk命令,每行都是一个独立的script
。
script 格式如下:
BEGIN { action }
pattern { action }
END { action }
脚本通常是被单引号或双引号包住,一个awk脚本通常由四部分组成:
-
BEGIN { action }
语句块,awk 执行pattern { action }
前要执行的脚本。 -
pattern { action }
语句块,决定动作语句何时触发,可以是以下任意一种:- 正则表达式:使用通配符的扩展集。
- 关系表达式:使用运算符进行操作,可以是字符串或数字的比较测试。
- 模式匹配表达式:使用运算符
~
(匹配)和~!
(不匹配)。
-
END { action }
语句块,awk 执行pattern { action }
后要执行的脚本。 -
action部分,决定对数据如何处理,由一个或多个命令、函数、表达式组成,之间由换行符或分号隔开,并位于大刮号内。常见的action包括:变量或数组赋值、输出命令、内置函数、控制流语句。
BEGIN { action }
、pattern { action }
、END { action }
都是可选项目。
awk 工作流
-
第一步: 执行
BEGIN { commands }
语句块中的语句。在awk从输入输出流中读取行之前执行,通常在BEGIN语句块中执行如变量初始化,打印输出表头等操作。
-
第二步:**从文件或标准输入中读取一行,然后执行
pattern { commands }
语句块。**它逐行读取数据,从第一行到最后一行重复这个过程,直到读取完所有行。pattern语句块中的通用命令是最重要的部分,它也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行。
{}
类似一个循环体,会对文件中的每一行进行迭代,通常将变量初始化语句放在BEGIN语句块中,将打印结果等语句放在END语句块中。 -
第三步:当读至输入流末尾时,执行
END { command }
语句块。在awk从输入流中读取完所有的行之后执行,比如打印所有行的分析结果,它也是一个可选语句块。
awk 示例
示例文件
[root@server ~ 19:23:44]# cat << 'EOF' > employee.txt
> 1) 张三 技术部 23
> 2) 李四 人力部 22
> 3) 王五 行政部 23
> 4) 赵六 技术部 24
> 5) 朱七 客服部 23
> EOF
示例1: 打印雇员信息。
[root@server ~ 19:27:27]# awk '{print}' employee.txt
1) 张三 技术部 23
2) 李四 人力部 22
3) 王五 行政部 23
4) 赵六 技术部 24
5) 朱七 客服部 23
示例2: 通过读取awk脚本,打印雇员信息。
[root@server ~ 19:28:12]# echo {print} > test3
[root@server ~ 19:29:01]# awk -f test3 employee.txt
1) 张三 技术部 23
2) 李四 人力部 22
3) 王五 行政部 23
4) 赵六 技术部 24
5) 朱七 客服部 23
示例3: 输出特定隔行。
[root@server ~ 19:29:25]# awk '/张三/{print}' employee.txt
1) 张三 技术部 23
#等同于
[root@server ~ 19:30:22]# awk '/张三/' employee.txt
1) 张三 技术部 23[root@server ~ 19:31:04]# awk '/张三/{print $0}' employee.txt
1) 张三 技术部 23
$0
,代表整行记录。
示例4: 统计满足特定条件的记录数。
AWK 中的所有变量都不需要初始化,并且会自动初始化为
0
。
[root@server ~ 19:32:04]# awk '
> /术/ { count=count+1 }
> END { print "Count="count }' employee.txt
Count=2
示例5: 输出总长度大于 10 的行。
AWK 提供了一个内建的函数 **length(arg)∗∗用于返回字符串‘arg)** 用于返回字符串 `arg)∗∗用于返回字符串‘arg` 的总长度。
如果要获取某行的总长度,可以使用下面的语法:
length($0)
。同样的,如果要获取某列/字段的总长度,可以使用语法:
length($n)
。如果要判断某行的字符是否大于/小于/等于 N ,可以使用下面的语法:
length($0) > N
。
[root@server ~ 19:39:37]# awk 'length($0)>10 {print $0}' employee.txt
1) 张三 技术部 23
2) 李四 人力部 22
3) 王五 行政部 23
4) 赵六 技术部 24
5) 朱七 客服部 23
awk 综合示例
示例文件结构:
- 每个雇员独占一行
- 每个雇员都包括以下字段:序号,名字,部门,年龄
- 每一行的多个字段之间使用空白作为分隔符,空白分隔符一般是空格 ( ) 或者制表符
\t
问题
我们想要获得以下输入结果
序号 姓名 部门 年龄
-------------------
1) 张三 技术部 23
2) 李四 人力部 22
3) 王五 行政部 23
4) 赵六 技术部 24
5) 朱七 客服部 23
-------------------
分析
从上面的结果中可以看出,整个输出结果分为三大部分
-
表头
序号 姓名 部门 年龄 -------------------
-
数据
每个雇员一样,且有着以下的结构
1) 张三 技术部 23 2) 李四 人力部 22 3) 王五 行政部 23 4) 赵六 技术部 24 5) 朱七 客服部 23
-
表尾
-------------------
根据我们刚刚学到的知识,AWK 程序结构分为三大部分,BEGIN 和 END 只会执行一次,看起来刚好可以用来输出表头,而 AWK 主体代码,是针对每一行执行的,因此,刚好可以用来输出数据。
解答
表头
为了输入表头,我们可以使用下面的 Shell 语句
[root@server ~ 19:49:30]# awk '
BEGIN { printf "序号 名字 部门 年龄\n-------------------\n" }'
序号 名字 部门 年龄
-------------------
因为表头部分不需要处理输入文件,也不需要处理输入文件中的每一行,所以 AWK 主体代码都是可以忽略的,甚至包括输入文件都是可以忽略的。
数据
对比想要的结果和输入的文件,可以看出输出结果并并没有对每一行做特殊处理,直接显示就好
因此,只需要在 BEGIN
块后面直接添加 { print }
,添加完代码如下:
[root@server ~ 19:58:11]# awk '
BEGIN { printf "序号 名字 部门 年龄\n-------------------\n" } {print} END {printf "-------------------\n"}' employee.txt
序号 名字 部门 年龄
-------------------
1) 张三 技术部 23
2) 李四 人力部 22
3) 王五 行政部 23
4) 赵六 技术部 24
5) 朱七 客服部 23
-------------------
awk 命令选项
–help 选项
用于输出 awk
命令的帮助信息。
[root@server ~ 19:58:36]# awk --help
Usage: awk [POSIX or GNU style options] -f progfile [--] file ...
Usage: awk [POSIX or GNU style options] [--] 'program' file ...
POSIX options: GNU long options: (standard)-f progfile --file=progfile-F fs --field-separator=fs-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|no-ext] --lint[=fatal|invalid|no-ext]-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 --versionTo report bugs, see node `Bugs' in `gawk.info'
which is section `Reporting Problems and Bugs' in the
printed version. This same information may be found at
https://www.gnu.org/software/gawk/manual/html_node/Bugs.html.
PLEASE do NOT try to report bugs by posting in comp.lang.awk,
or by using a web forum such as Stack Overflow.gawk is a pattern scanning and processing language.
By default it reads standard input and writes standard output.Examples:awk '{ sum += $1 }; END { print sum }' fileawk -F: '{ print $1 }' /etc/passwd
-F 选项
**作用:**用于定义awk程序的分隔符。awk程序的分隔符,是用于分割同一行数据的分割符号。默认分隔符是:空格。
语法:-F fs
或者 --field-separator=fs
**示例:**打印用户名和家目录
[root@server ~ 20:22:25]# head -n 1 /etc/passwd
root:x:0:0:root:/root:/bin/bash[root@server ~ 20:22:02]# head -n1 /etc/passwd | awk -F : '{print $1 " " $6}'
root /root
awk 内置变量
在上述的示例中,我们使用了很多 awk
内置变量。
我们可以使用 -d
选项,导出awk内置的预定义变量到 file
文件中。
格式:--dump-variables[=file]
或者-d[file]
awk默认导出的内置的预定义变量保存在文件 awkvars
文件中。
示例:
[root@server ~ 20:22:58]# awk -d ''
[root@server ~ 20:40:35]# cat awkvars.out
ARGC: 1
ARGIND: 0
ARGV: array, 1 elements
BINMODE: 0
CONVFMT: "%.6g"
ERRNO: ""
FIELDWIDTHS: ""
FILENAME: ""
FNR: 0
FPAT: "[^[:space:]]+"
FS: " "
IGNORECASE: 0
LINT: 0
NF: 0
NR: 0
OFMT: "%.6g"
OFS: " "
ORS: "\n"
RLENGTH: 0
RS: "\n"
RSTART: 0
RT: ""
SUBSEP: "\034"
TEXTDOMAIN: "messages"
我们把上面的输出结果整理如下:
变量 | 数据类型 | 默认值 |
---|---|---|
ARGC | number | 1 |
ARGIND | number | 0 |
ARGV | array | 1 elements |
BINMODE | number | 0 |
CONVFMT | string | “%.6g” |
ERRNO | number | 0 |
FIELDWIDTHS | string | “” |
FILENAME | string | “” |
FNR | number | 0 |
FS | string | " " |
IGNORECASE | number | 0 |
LINT | number | 0 |
NF | number | 0 |
NR | number | 0 |
OFMT | string | “%.6g” |
OFS | string | " " |
ORS | string | “\n” |
RLENGTH | number | 0 |
RS | string | “\n” |
RSTART | number | 0 |
RT | string | “” |
SUBSEP | string | “\034” |
TEXTDOMAIN | string | “messages” |
上面列出的这些变量,在 AWK 中扮演整重要的作用。
变 量 | 描述 |
---|---|
ARGC | 命令行参数的数目。 |
ARGIND | 命令行中当前文件的位置(从0开始算)。 |
ARGV | 包含命令行参数的数组。 |
CONVFMT | 数字转换格式(默认值为%.6g) |
ENVIRON | 环境变量关联数组。 |
ERRNO | 最后一个系统错误的描述。 |
FIELDWIDTHS | 字段宽度列表(用空格键分隔)。 |
FILENAME | 当前文件名。 |
FNR | 同NR,但相对于当前文件。 |
FS | 字段分隔符(默认是任何空格)。 |
IGNORECASE | 如 果为真,则进行忽略大小写的匹配。 |
NF | 当前记录中的字段数。 |
NR | 当前记录数(读入第几行数据)。 |
OFMT | 数字的输出格式(默认值是%.6g)。 |
OFS | 输 出字段分隔符(默认值是一个空格)。 |
ORS | 输出记录分隔符(默认值是一个换行符)。 |
RLENGTH | 由 match函数所匹配的字符串的长度。 |
RS | 记录分隔符(默认是一个换行符)。 |
RSTART | 由 match函数所匹配的字符串的第一个位置。 |
SUBSEP | 数组下标分隔符(默认值是\034)。 |
$n | 当前记录的第n个字段,字段间由 FS分隔。 |
$0 | 完整的输入记录。 |
NF 变量
变量 NF
是 Number of Fields
的缩写,用于表示当前行分割出来的字段/列数量。
下面的命令输出了当前每一行有被分割出了多少个字段
[root@server ~ 20:44:54]# echo -e '一 二\n一 二 三 四\n一 二 三' | awk '{print $0 "\t",NF}'
一 二 2
一 二 三 四 4
一 二 三 3
变量 NF
还可以用于条件判断。
例如,下面的命令输出了哪些字段/列大于 2 的行。
[root@server ~ 20:45:44]# echo -e '一 二\n一 二 三 四\n一 二 三' | awk ' NF>2'
一 二 三 四
一 二 三
#或者
[root@server ~ 20:45:58]# echo -e '一 二\n一 二 三 四\n一 二 三' | awk 'NF>2 {print $0}'
一 二 三 四
一 二 三
NR 变量
变量 NR
是 Number of Record
的缩写,用于表示当前行的行号,也就是处理到第几行。行编号从 1 开始。
下面的代码,用于在每一行数据的前面输出当前的行号
[root@server ~ 20:48:13]# echo -e '一 二\n一 二 三 四\n一 二 三' | awk '{print NR "."$0}'
1.一 二
2.一 二 三 四
3.一 二 三
变量 NR
还可以用于条件判断,例如下面的命令用于输出行号小于 3 的行,也就是第一第二行。
[root@server ~ 20:48:17]# echo -e '一 二\n一 二 三 四\n一 二 三' | awk 'NR < 3'
一 二
一 二 三 四