linux工具-awk
1. 基本知识
1.1. 名称由来
awk是其设计者名字首字母.
1.2. 语法格式
awk [options] 'pattern {action}' filename
1.3. 执行流程
对如下语句:
awk 'BEGIN {action1} pattern {action2} END {action3}' filename
执行流程如下:
- 执行BEGIN {action1}语种块中的语句.
- 从文件或STDIN逐行读取, 对每一行执行pattern {action2}, 直到全部读取完成.
- 执行END {action3}语种块中的语句.
例子: 打印每一行, 并且在开头和结尾分别打印Start和END. print语句不带参数时就打印整行内容. $0代表整行内容.
awk ‘{printf “Start.%s.End”, $0}’ file.txt
例子:对第2列进行累加, 在BEGIN中为i赋初值, 在END中打印i(累加结果).
$ echo -e "a 1 a\na 2 a\na 3 a" | \
> awk 'BEGIN {i=0} {i+=$2} END {print i}'
6
1.4. 术语解释
术语 | 说明 |
---|---|
记录 | awk把每一个以换行符结束的行称为一个记录, NR即记录的个数 |
域 | 记录中每个单词称做"域", 默认以空格或Tab分隔, NF即域的个数. |
2. awk的选项: options
选项 | 说明 |
---|---|
-v | 参数传递, 为参数赋值 |
-f | 指定脚本文件 |
-F | 指定分隔符 |
-V | 查看awk版本号 |
例子1:指定列分隔符
文件内容
$ cat demo.txt
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
通过-F指定列分隔符
$ # -F和:之间没有空格
$ awk -F: '{printf "%-6s %-9s %s\n", $1, $6, $7}' demo.txt
root /root /bin/bash
daemon /usr/sbin /usr/sbin/nologin
bin /bin /usr/sbin/nologin
sys /dev /usr/sbin/nologin
sync /bin /bin/sync
$
$ # -F和:之间有空格, 这时分隔符最好放到引号中, 否则使用#等分隔时会报错.
$ awk -F ':' '{printf "%-6s %-9s %s\n", $1, $6, $7}' demo.txt
root /root /bin/bash
daemon /usr/sbin /usr/sbin/nologin
bin /bin /usr/sbin/nologin
sys /dev /usr/sbin/nologin
sync /bin /bin/sync
通过-v FS指定列分隔符(FS是内置变量, 表示输入字段的列分隔符)
$ awk -v FS=: '{printf "%-6s %-9s %s\n", $1, $6, $7}' demo.txt
root /root /bin/bash
daemon /usr/sbin /usr/sbin/nologin
bin /bin /usr/sbin/nologin
sys /dev /usr/sbin/nologin
sync /bin /bin/sync
3. 处理文本: pattern
awk_script由pattern(模式)和Action(动作)组成.
关键词 | 中文名称 | 作用 |
---|---|---|
pattern | 模式 | 用来选取待处理的行, 可以为空, 表示处理每一行. |
action | 动作 | 对行做什么操作. |
例如:
awk 'BEGIN {action1} pattern {action2} END {action3}' filename
3.1 模式pattern
有4种模式, 用来选取待处理的行, 可以为空, 表示处理每一行.
序号 | 模式 | 说明 |
---|---|---|
1 | /正则表达式/ | 正则匹配 |
2 | 关系表达式 | 使用运算符进行操作, 比如字符串、数字的比较测试. |
3 | 模式匹配表达式 | 用运算符:~和~!, 分别表示匹配、不匹配. |
4 | BEGIN/END语句块、pattern语句块 | . |
3.2 动作action
Action由一个或多个命令/函数/表达式组成, 它们之间用换行符或分号隔开.
action主要有以下类型:
序号 | 动作 |
---|---|
1 | 变量或数组赋值 |
2 | 输出命令 |
3 | 内置函数 |
4 | 控制流语句 |
注意:
序号 | 语句 | 说明 |
---|---|---|
1 | BEGIN | 只在开始执行一次, 是可选的, 默认无BEGIN action. |
2 | pattern | 对匹配pattern的行进行操作, pattern是可选的, 默认对每一行进行action2, {action2}也是可选的, 默认打印匹配pattern的行, 但是pattern和{action2}必须出现一个, 不能都省略. |
3 | END | 只在结尾执行一次, 是可选的, 默认无END action. |
例子1:
输入文件内容:
$ cat a.txt
line first 1
line second 2
line third 3
line forth 4
line fifth 5
line sixth 6
line seventh 7
使用BEGIN、END等
$ # 在BEGIN的action中, 先打印一行内容, 再给i赋初值
$ # 在遍历line的语句中, 打印第2、3列, 并对第3列累加
$ # 在END的action中, 打印第3列的累加结果
$ awk 'BEGIN {print "C2", "C3"; i=0} {print $2, $3; i+=$3} END {print "total=",i}' a.txt
C2 C3
first 1
second 2
third 3
forth 4
fifth 5
sixth 6
seventh 7
total= 28
注意:
1. 在print语句中,
字符串要写在双引号里,
字符串之间用逗号分隔,
变量可以直接赋初值,
变量使用时不能带双引号
2. 变量赋值和使用时不需要带$号($1/$2等不受此限制)
3. 多个action语句之间使用分号分隔.
4. 运算符
类别 | 运算符 | 说明 |
---|---|---|
赋值运算符 | = | 赋值语句 |
逻辑运算符 | || | 逻辑或 |
&& | 逻辑与 | |
正则运算符 | ~ | 正则匹配 |
~! | 正则不匹配 | |
关系运算符 | <, <= | 小于, 小于等于 |
>, >= | 大于, 大于等于 | |
== | 等于 | |
!= | 不等于 | |
算术运算符 | +, - | 加, 减 |
*, /, % | 乘, 除, 取余 | |
+, -, ! | 一元加, 一元减, 逻辑非 | |
^, *** | 幂 | |
++, -- | 自增, 自减 | |
其他运算符 | $ | 字段引用 |
空格 | 字符串连接 | |
?: | 三元运算符 | |
in | 元素是否存在于数组中 |
例: 只处理奇数行并输出
# 说明: NR是行号, $1是第一列内容, NF是当前行列数, $(NF-1)是倒数第二列内容, $NF是最后一列内容
$ awk -F: 'NR%2==1 {printf "%s) %-6s %-9s %s\n", NR, $1, $(NF-1), $NF}' demo.txt
1) root /root /bin/bash
3) bin /bin /usr/sbin/nologin
5) sync /bin /bin/sync
例: 只处理$1等于root或bin的行(使用||)
$ awk -F: '$1=="root"||$1=="bin" {printf "%s) %-6s %-9s %s\n", NR, $1, $(NF-1), $NF}' demo.txt
1) root /root /bin/bash
3) bin /bin /usr/sbin/nologin
5. 内置变量
范围 | 内置变量 | 说明 |
---|---|---|
命令行 | ARGC | 命令行参数个数 |
ARGV | 命令行参数数组 | |
文件名 | FILENAME | 当前文件名 |
计数 | FNR | 各文件分别计数的行号 |
NF | 当前行的字段个数(当前行分成了几列) | |
NR | 行号 | |
分隔符 | FS | 输入字段分隔符, 默认为空白字符 |
OFS | 输出字段分隔符, 默认为空白字符 | |
RS | 输入记录分隔符(输入换行符) | |
ORS | 输出记录分隔符(输出换行符) | |
记录 | $0 | 完整的输入记录(当前行所有内容) |
$n | 当前记录的第n个字段(从1开始), 字段间由FS分隔 |
例: 使用NF
# NF表示字段数, 本例中NF=7,
# $NF即$7, 表示最后一个字段,
# $(NF-1), 表示倒数第二字段
$ awk -F: '{printf "%-6s %-9s %s\n", $1, $(NF-1), $NF}' demo.txt
root /root /bin/bash
daemon /usr/sbin /usr/sbin/nologin
bin /bin /usr/sbin/nologin
sys /dev /usr/sbin/nologin
sync /bin /bin/sync
例: 使用NR, NR表示当前行的行号
$ awk -v FS=: '{printf "%s) %-6s %-9s %s\n", NR, $1, $(NF-1), $NF}' demo.txt
1) root /root /bin/bash
2) daemon /usr/sbin /usr/sbin/nologin
3) bin /bin /usr/sbin/nologin
4) sys /dev /usr/sbin/nologin
5) sync /bin /bin/sync
6. 变量
awk中, 变量不需要定义就可以直接使用, 变量类型可以是数字或字符串.
例:如果第一个域匹配test, 则把第二第三个域相加并打印.
awk '$1 ~ /test/ {count=$2+$3; print count}' filename
域变量可以修改:
例: 如果第一个域等于"root", 则把它赋值为test并打印.
awk '$1=="root" {$1="test"; print}' filename
7. 条件语句
if语句
如果第三个域大于3, 则打印一个第二第三域和一个"match"字符, 各字符之间可以有空格, 也可以没有, 字符串要写到双引号中.
awk '{if ($3>3) print $2 "\t" $3 "\t" "match"}' a.txt
if-else if-else语句
有多个分支, 各分支的语句要写在大括号中.
awk '{if ($3<=2) {print "0~2"} else if ($3<=4) {print "3~4"} else {print "5~n"}}' a.txt
8. 循环语句
- awk有三种循环:while、for、special for
- 可以使用break和continue.
- next语句从输入文件中读取一行, 然后从头开始执行awk脚本.
- exit语句用于结构awk程序, 但不会略过END块.
例子:
awk '{i=1; while(i<=NF){print i, $i; i++}; print "------"}' a.txt
说明:
- NF是当前行(记录)的字段(域)数量, $i是第i个字段(从1开始).
- 注意:print语句中, i和$i是不同的东西, i是循环变量, $i是第i个字段.
- 本例以字段数为循环条件, 遍历每个字段并打印.
例子:
awk '{for (i=1;i<=NF;i++) {print i, $i}; print "------"}' a.txt
说明:作用同上, 将while语句改为for语句实现.
special for用来遍历关联数组.见关联数组.for(i in name) {print i, name[i]}
9. 数组
在awk中数据的下标可以是数字, 也可以是字母(称为关联数组, 类似于python中的字典).
例子:
awk '{name[i++]=$2} END {for (i=0;i<NR;i++) {print i, name[i]}}' a.txt
说明:
- 将每行的第二字段存入数组, 在结尾遍历数组并打印.
- name是一个数组, 不用声明, 直接赋值.
- 给数组赋值时, 直接对下标赋值, 不需要管该下标是否存在.
- 数组下标变量i自动初始化为0, 然后每处理一个记录自动加1.
- NR是当前行的行号(从1开始), 在END块中NR自动变成总行数, 用来遍历数组.
例子:
awk '/s/ {name[NR]=$2} END {for(i in name) {print i, name[i]}}' a.txt
说明:
- 如果某行匹配/s/, 则给数组赋值, 下标是行号, 值是$2, 在结尾遍历数组.
- name的下标虽然是数字, 但可以是不连续的.
10. 内置函数
https://www.gnu.org/software/gawk/manual/html_node/Built_002din.html#Built_002din
函数 | 作用 |
---|---|
toupper() | 字符串转为大写 |
tolower() | 字符串转为小写 |
length() | 返回字符串长度 |
substr() | 返回子字符串 |
sin() | 正弦 |
cos() | 余弦 |
sqrt() | 平方根 |
rand() | 随机数 |
例: 使用toupper()将第一字段转为大写
$ awk -F: '{printf "%s) %-6s %-9s %s\n", NR, toupper($1), $(NF-1), $NF}' demo.txt
1) ROOT /root /bin/bash
2) DAEMON /usr/sbin /usr/sbin/nologin
3) BIN /bin /usr/sbin/nologin
4) SYS /dev /usr/sbin/nologin
5) SYNC /bin /bin/sync