awk,一种处理文本文件的语言,是一个强大的文本分析工具。叫 awk是因为其取了三位创始人 Alfred Aho,Peter Weinberger, 和 Brian Kernighan 的 Family Name 的首字符。awk对分割后的列处理,比较方便。
1. 基础语法
awk对文本进行逐行扫描并处理。awk中使用的命令也是awk自有的,而非linux中的。比如print
。
awk内置变量在awk命令中使用时,不需要加$
|
awk命令常见的几种形式:
awk '命令' 文件名
awk '查找模式 [命令]' 文件名
awk [-F 域分割符] '命令' 文件名 # 默认域分割符是空格
上述'命令'都要用{}括起来,查找模式不需要。
常见运算符:
运算符 | 描述 |
---|---|
/str/ | str相当于是raw的,单独用于查找模式中时表示整行中要包含str, |
= += -= *= /= %= ^= **= | 赋值 |
?: | C条件表达式 |
|| | 逻辑或 |
&& | 逻辑与 |
~ 和 !~ | 匹配正则表达式和不匹配正则表达式,例:$1 ! /regexp/ |
< <= > >= != == | 关系运算符 |
空格 | 连接 |
+ - | 加,减 |
* / % | 乘,除与求余 |
+ - ! | 一元加,减和逻辑非 |
^ *** | 求幂 |
++ -- | 增加或减少,作为前缀或后缀 |
$ | 字段引用 |
in | 数组成员 |
常见符号和指令:
命令 | 含义 |
---|---|
$0 | 读入的整行内容 |
$N | N大于0,按分割符分割后的第N列内容 |
打印命令,pirnt a,b,c 打印时逗号被输出分割符替代 | |
NR | awk内置变量,当前行的行号。awk内置变量在awk命令中使用时,不需要加$ |
FS | awk内置变量,输入域的分隔符,默认为空格,指定FS=":" 等同于 -F : |
OFS | awk内置变量,输出域的分隔符,默认为空格,print打印时各列间的分割符 |
> | 重输出,awk '{print $1 >"t2.txt" }' t.txt |
#样例
> cat awk.txt
Jack 1243 1971
Mike 3123 1980
Tom 3451 1990
> awk '{print $0}' awk.txt
Jack 1243 1971
Mike 3123 1980
Tom 3451 1990
> awk '{print NR,$1,$3}' awk.txt
1 Jack 1971
2 Mike 1980
3 Tom 1990
> awk '$2 ~ 1243' awk.txt
Jack 1243 1971
> awk '$2 ~ 124355' awk.txt
> awk '$1 ~ Jack' awk.txt #Jack当做变量赋值为空,所以都匹配
Jack 1243 1971
Mike 3123 1980
Tom 3451 1990
> awk '$1 ~ "Jack"' awk.txt # 或 awk '$1 ~ /Jack/' awk.txt
Jack 1243 1971
> awk '$2 ~ "[0-9]*"' awk.txt
Jack 1243 1971
Mike 3123 1980
Tom 3451 1990
> awk '$2 ~ /[0-9]*/' awk.txt
Jack 1243 1971
Mike 3123 1980
Tom 3451 1990
> awk '/Jack/' awk.txt
Jack 1243 1971
> awk '/"Jack"/' awk.txt #引号也被当做匹配字符,/str/直接的str相当于是raw的
> awk '/Jack/ {print $1,$3}' awk.txt
Jack 1971
> awk -F: '{print $1,$7}' /etc/passwd
bin /bin/bash
daemon /bin/bash
> awk '{FS=":";OFS="#";print $1,$7}' /etc/passwd
bin#/bin/bash
daemon#/bin/bash
2. BEGIN和END模块
不管位置如何,BEGIN总是先执行,END总是最后执行。
'{命令}'增加模块:
'BEGIN{...} {命令} END{...}'
awk总是数据输入驱动的,如果仅运行 awk '{命令}'
则等待键盘输入,输入一行,命令执行一次。但如果命令中有且仅有BEGIN模块时,则不需要输入驱动。
> awk 'BEGIN{ print "Good Man"}'
Good Man
3. 流程控制语句
awk具有与C语言十分类似的控制流程功能,如if/else,while, do-whiel,for循环等。
# if 控制
awk '{if($3>1980){print $0}}' awk.txt
# while
awk '{while($3>1980){print $0;exit}}' akw.txt # 打印一个就退出
4. 数学计算
内置的一些数学函数时bash没有的。
名称 | 返回值 |
---|---|
exp(x) | e的x次幂 |
int(x) | x的整数部分 |
log(x) | 以e为底的x的对数 |
rand() | 0到1之间的随机数 |
srand(x) | x是rand()的种子 |
sqrt(x) | x的平方根 |
atan2(y,x) | |
cos(x) | |
sin(x) |
> awk 'BEGIN{print int(15.2),sqrt(6)}'
15 2.44949
5. 字符串处理
awk提供了丰富的字符串处理函数,比较常见的有
函数名 | 作用 |
---|---|
index(str,substr) | 返回子串substr在str中第一次出现的位置 |
substr(str,k,m) | 返回str中从k到m位置的子串 |
length(str) | 返回str的长度 |
> awk 'BEGIN{print length(15.2)}' awk 'BEGIN{print length(15.2)}' #str加不加引号都可以
4
> awk 'BEGIN{print length("15.2")}'
4
6. 调用系统bash命令
awk可以通过system
函数调用bash命令或脚本。print cmd | “/bin/bash”
也可调用系统命令。
注意1:如果system()
括号里面的参数没有加上双引号的话,awk认为它是一个变量,它会从awk的变量里面把它们先置换为常量,然后再回传给shell。
注意2:awk是新开一个shell,无论使用system()
还是print cmd | “/bin/bash”
,在相应的cmdline参数送回给shell,所以要注意当前shell变量与新开shell变量问题。要想在system中还想使用,则需要在awk外部用export。
# 例1
> awk 'BEGIN{system(date)}' # date当做变量,什么也不输出
> awk 'BEGIN{system("date")}'
Mon Oct 31 22:10:51 CST 2022
# 例2
> awk 'BEGIN{system("echo abc")}'
abc
> awk 'BEGIN{v1="echo";v2="abc";system(v1" "v2)}'
abc
> awk 'BEGIN{v1="echo";v2="abc";system(v1 v2)}' # 命令行没用空格
sh: echoabc: command not found
> awk 'BEGIN{v1=echo;v2=abc;system(v1" "v2)}' # echo和abc当做变量了
> awk 'BEGIN{abc="aaa";v1=echo;v2=abc;system("echo "v1" "v2)}'
aaa
# 例3. 解密a.txt中每一行数据
> awk '{cmd="./test decrypt "$0; system(cmd)}' a.txt > b.txt
# print
> awk 'BEGIN{print "echo","abc"| "/bin/bash"}'
abc
> awk 'BEGIN{print "echo","abc",";","echo","123"| "/bin/bash"}' # 注意分割多行命令的分号用双引号括起来
abc
123
# 作用域问题
> var=12345
> export var2=12345
# 基础验证
> awk 'BEGIN{print var}'
> awk 'BEGIN{print var2}'
--awk命令系统中,就没有var2这样一个变量
# 注意{var}和var的区别
> awk 'BEGIN{system("echo $var")}'
> awk 'BEGIN{system("echo ${var}")}'
> awk 'BEGIN{system("echo $var2")}'
12345 --awk的shell系统中,var2是存在的,且不用大括号也能识别
> awk 'BEGIN{system("echo ${var2}")}'
12345
> awk 'BEGIN{print "echo","$var"| "/bin/bash"}'
> awk 'BEGIN{print "echo","${var}"| "/bin/bash"}'
> awk 'BEGIN{print "echo","${var2}"| "/bin/bash"}'
12345
> awk 'BEGIN{print "echo","$var2"| "/bin/bash"}'
12345
7. awk命令脚本
同sed,awk也是可以将所有命令写在一个脚本文件中的:
awk -f awk脚本名
若在脚本第一行加上#!/bin/awk -f
,则可直接运行脚本:
awk脚本名