awk是专门为文本处理设计的编.程语言,也是一个应用程序,几乎所有Linux发行版本都自带这个程序。我们通常用它进行数据扫描、过滤、统计汇总工作。
awk工作原理
它与grep、sed命令一样都是以行为单位读取文本的,默认以空格或Tab键为分隔符,将分割所得的各个字段保存到内建变量中供后续使用。
命令格式如下:
awk "[选项1] {操作1;操作2} [选项2] {操作3;操作4} ..." 文件名
awk -f 脚本文件 文件名
awk语法由一系列选项和操作组成,在花括号内可以有多个操作,在多个操作之间是有分号分隔,在多个选项和操作之间可以有若干空格,也可以没有
选项说明:
-F fs or --field-separator fs:相当于内建变量“FS”,指定分割符为fs,默认为空格或Tab制表符;
-f scripfile or --file scriptfile:从文件中读取awk指令,用来代替命令行中输入的命令;
-v var=value or --asign var=value:设置一个变量并且附上初值。
常见的内置变量如下:
内置变量 | 说明 |
---|---|
$0 | 当前记录(作为单个变量),即当前处理的行的字段个数 |
FS | 列分割符指定每行文本的字段分隔符,默认为空格或制表位。也可用选项"-F"表示 |
NF | 当前处理行的字段个数,即列数,从1开始 |
NR | 当前记录中的行数,从1开始 |
$n | 当前处理行的第n个字段(第n列) |
RS | 行分隔符。awk从文件上读取资料时,将根据RS的定义把资料切割成许多条记录,而awk一次仅读入一条记录,以进行处理。预设值是’\n’ |
FILENAME | 被处理的文件名 |
FNR | 当awk处理多个文件时,分别对每个文件的行数进行计数 |
ORS | 更改行换行符 |
OFS | 更改列分割符 |
ARGV | 表示是一个数组,这个数组中保存的是命令行所给定的参数 |
ARGC | 表示参数的数量,也可以理解为ARGV数组的长度 |
运算符
运算符 | 描述 |
---|---|
= += -= *= /= %= ^= **= | 赋值 |
?: | C语言中的三目运算符 |
< <= > >= != == | 关系运算 |
+ - * / % | 算术运算 |
^ ** | 求幂 |
++ -- | 自增和自减 |
||和&& | 逻辑或/与 |
$ | 字段引用 |
in | 数组成员 |
示例,编写一个test.txt文本
root@ubuntu:/home/zgx/Desktop# cat test.txt # 查看文本内容
this is a test file
hello,world!
bye byeha
year, month, day, hour, minute, second
root@ubuntu:/home/zgx/Desktop# awk "{print NF}" test.txt # 使用NF显示每行的列数
5
1
2
6
root@ubuntu:/home/zgx/Desktop# awk "{print $NR}" test.txt # 打印显示当前每行记录
this is a test file
hello,world!
bye byeha
year, month, day, hour, minute, second
使用$1,$4打印第1列、第4列的内容
root@ubuntu:/home/zgx/Desktop# awk '{print $1,$4}' test.txt # 普通输出
this test
hello,world!
bye
year, hour,
root@ubuntu:/home/zgx/Desktop# awk '{printf "%-10s %-10s\n",$1,$4}' test.txt # 格式化输出
this test
!
bye
year, hour,
注意:print与printf的区别:
1)printf用于格式化输出
2)printf默认是不带换行符号的,所以要换行需要带上\n
指定英文逗号“,”为分隔符
root@ubuntu:/home/zgx/Desktop# awk -F',' '{print $1,$4}' test.txt
this is a test file
hello
bye byeha
year hour
指定多个分割符输出(首先使用空格,然后在使用其他分割符)
root@ubuntu:/home/zgx/Desktop# awk -F '[, ]' '{print NF}' test.txt # 查看分隔后的每行列数
5
2
2
11
root@ubuntu:/home/zgx/Desktop# awk -F '[, ]' '{print $1,$2,$3}' test.txt
this is a
hello world!
bye byeha
year [空格] month
打印第i到第j行的内容(两种方法)
root@ubuntu:/home/zgx/Desktop# awk 'NR==2,NR==4{print}' test.txt # 打印第2到第4的内容
root@ubuntu:/home/zgx/Desktop# awk 'NR==2,NR==4' test.txt # {print}可要可不要
hello,world!
bye byeha
year, month, day, hour, minute, second
root@ubuntu:/home/zgx/Desktop# awk '(NR>=2)&&(NR<=4){print}' test.txt # 打印第2到第4的内容
root@ubuntu:/home/zgx/Desktop# awk '(NR>=2)&&(NR<=4)' test.txt # {print}可要可不要
hello,world!
bye byeha
year, month, day, hour, minute, second
打印第i、第j行的内容
root@ubuntu:/home/zgx/Desktop# awk 'NR==2 || NR==4' test.txt # 打印第2、第4行的内容
hello,world!
year, month, day, hour, minute, second
显示text2.txt文本内容如下
root@ubuntu:/home/zgx/Desktop# cat test2.txt
this is a test file
hello,world!
bye byeha
year, month, day, hour, minute, second
hahaha
hello everybody
aaaaaaaaa
输出以h、he开头的行
root@ubuntu:/home/zgx/Desktop# awk '/^h/{print}' test2.txt # 打印以h开头的行
hello,world!
hahaha
hello everybody
root@ubuntu:/home/zgx/Desktop# awk '/^he/' test2.txt # 打印以he开头的行
hello,world!
hello everybody
输出以d!为结尾的行
root@ubuntu:/home/zgx/Desktop# awk '/d!$/' test2.txt
hello,world!
输出第2列包含字符b的行
root@ubuntu:/home/zgx/Desktop# awk '$2 ~ /b/' test2.txt
bye byeha
hello everybody
root@ubuntu:/home/zgx/Desktop# awk '$2 !~ /b/' test2.txt # 输出第2列不包含字符b的行
this is a test file
hello,world!
year, month, day, hour, minute, second
hahaha
aaaaaaaaa
显示test3.txt文本的内容如下:
root@ubuntu:/home/zgx/Desktop# cat test3.txt
101 this is a test file
102 hello world!
203 bye byeha
204 year, month, day, hour, minute, second
205 fawff
no number
206,aaaaaaaa
输出第i列数值在指定范围的行
root@ubuntu:/home/zgx/Desktop# awk '$1>200' test3.txt # 输出第1列数值大于200的行
203 bye byeha
204 year, month, day, hour, minute, second
205 fawff
no number
206,aaaaaaaa
root@ubuntu:/home/zgx/Desktop# awk '$1>300' test3.txt # 输出第1列数值大于300的行
no number
输出第1列小于100且第2列字符串为“hello”的行
root@ubuntu:/home/zgx/Desktop# awk '$1<200 && $2=="hello"' test3.txt
102 hello world!
输出以非h开头的行
root@ubuntu:/home/zgx/Desktop# awk '!/^h/' test2.txt # 打印以非h开头的行
this is a test file
bye byeha
year, month, day, hour, minute, second
aaaaaaaaa
输出第1列数值非大于200的行
root@ubuntu:/home/zgx/Desktop# awk '!($1>200)' test3.txt
101 this is a test file
102 hello world!
root@ubuntu:/home/zgx/Desktop# awk -F'[, ]' -va=1 -vb=sss '{print $1,$1+a,$1a,$1b}' test3.txt
101 102 1011 101sss
102 103 1021 102sss
203 204 2031 203sss
204 205 2041 204sss
205 206 2051 205sss
no 1 no1 nosss
206 207 2061 206sss
函数 | 说明 |
---|---|
length() | 返回字符串的长度 |
index() | 返回下标 |
tolower() | 转换成小写并返回字符串 |
toupper() | 转换成大写并返回字符串 |
substr() | 返回字符串中的子串 |
match() | 返回下标,但它不搜索子串 |
sub() | 替换匹配的第一个字符串序列,并返回整个字符串 |
gsub() | 替换匹配的所有字符串序列,并返回整个字符串 |
split() | 分割字符串并将各部分放到使用整数下标的数组中 |
打印各行字符串的长度
root@ubuntu:/home/zgx/Desktop# cat test2.txt
this is a test file
hello,world!
bye byeha
year, month, day, hour, minute, second
hahaha
hello everybody
aaaaaaaaa
root@ubuntu:/home/zgx/Desktop# awk '{print length()}' test2.txt
19
12
9
38
6
15
9
打印字符串长度超过15的行
root@ubuntu:/home/zgx/Desktop# awk 'length>15' test2.txt
this is a test file
year, month, day, hour, minute, second
字符串大小写转换
root@ubuntu:/home/zgx/Desktop# awk '{print $1, tolower($2), toupper($3)}' test2.txt
this is A
hello,world!
bye byeha
year, month, DAY,
hahaha
hello everybody
aaaaaaaaa
打印每行的最后两个字符
root@ubuntu:/home/zgx/Desktop# awk '{print substr($0,length($0)-1)}' test2.txt
le
d!
ha
nd
ha
dy
aa
默认情况下awk是从输入中读取一行字符串,然后对该行执行相应的命令,而有时候想在执行这些命令之前先进行一些其他的脚本命令,则可以使用BEGIN关键字,而END关键字的处理时机则刚好相反。
代码示例:
root@ubuntu:/home/zgx/Desktop# awk 'BEGIN{print "---file start---"} {print $1,$4} END{print "---file end---"}' test2.txt
---file start---
this test
hello,world!
bye
year, hour,
hahaha
hello
aaaaaaaaa
---file end---