1、简介
awk与grep、sed命令一样都是以行为单位读取文本的,默认以空格或Tab键为分隔符,将分割所得的各个字段保存到内建变量中供后续使用。
命令格式:
awk [选项] '命令' 文件名
选项说明:
- -F fs or --field-separator fs:相当于内建变量“FS”,指定分割符为fs,默认为空格或Tab制表符;
- -f scripfile or --file scriptfile:从文件中读取awk指令,用来代替命令行中输入的命令;
- -v var=value or --asign var=value:设置一个变量并且附上初值。
字段变量: - $0:整个文本行
- $1:文本行中第1个数据字段
- $2:文本行中第2个数据字段
- $n:文本行中第n个数据字段
2、基本用法
普通输出内容:
linrm@linrm-VirtualBox:~$ cat file1.txt
i am a test file!
thank you!
r u ok?
year, month, day, hour, minute, second
linrm@linrm-VirtualBox:~$ awk '{print $1,$4}' file1.txt # 普通输出
i test
thank
r
year, hour,
linrm@linrm-VirtualBox:~$ awk '{printf "%-8s %-10s\n",$1,$4}' file1.txt # 格式化输出
i test
thank
r
year, hour,
指定“,”为分割符:
linrm@linrm-VirtualBox:~$ awk -F, '{print $1,$4}' file1.txt
i am a test file!
thank you!
r u ok?
year hour
指定多个分割符输出(首先使用空格,然后在使用其他分割符):
linrm@linrm-VirtualBox:~$ awk -F '[, ]' '{print $1,$2,$4}' file1.txt
i am test
thank you!
r u
year
从文件中读取awk指令:
linrm@linrm-VirtualBox:~$ cat file.awk
{print $1,$4}
linrm@linrm-VirtualBox:~$ awk -f file.awk file1.txt
i test
thank
r
year, hour,
设置变量:
linrm@linrm-VirtualBox:~$ cat file2.txt
101 i am a test file!
102 thank you!
103 r u ok?
104 year, month, day, hour, minute, second
linrm@linrm-VirtualBox:~$ awk -va=1 -vb=sss '{print $1,$1+a,$1a,$1b}' file2.txt
101 102 1011 101sss
102 103 1021 102sss
103 104 1031 103sss
104 105 1041 104sss
3、运算符
运算符 | 描述 |
---|---|
= += -= *= /= %= ^= **= | 赋值 |
?: | C语言三目运算符 |
< <= > >= != == | 关系运算 |
+ - * / % | 运算 |
^ ** | 求幂 |
++ – | 自增自减 |
ll和&& | 逻辑或/与 |
和! | 匹配正则表达式与否 |
空格 | 连接 |
$ | 字段引用 |
in | 数组成员 |
过滤第一列大于102的行:
linrm@linrm-VirtualBox:~$ cat file2.txt
101 i am a test file!
102 thank you!
103 r u ok?
104 year, month, day, hour, minute, second
linrm@linrm-VirtualBox:~$ awk '$1>102' file2.txt
103 r u ok?
104 year, month, day, hour, minute, second
过滤第一列大于101并且第二列等于thank的行:
linrm@linrm-VirtualBox:~$ awk '$1 > 101 && $2 == "thank" {print $1,$2,$3}' file2.txt
102 thank you!
4、BEGIN/END关键字
这两个关键字的作用是指定脚本命令的运行时机,默认情况下awk是从输入中读取一行字符串,然后对该行执行相应的命令,而有时候想在执行这些命令之前先进行一些其他的脚本命令,则可以使用BEGIN关键字,而END关键字的处理时机则刚好相反。
linrm@linrm-VirtualBox:~$ awk 'BEGIN{print "---file start---"} {print $1,$4} END{print "---file end---"}' file2.txt
---file start---
101 a
102
103 ok?
104 day,
---file end---
5、内建变量
内建变量 | 说明 |
---|---|
$0 | 完整的输入记录 |
$1 $2 $n | 第1、2、n个字段 |
FS | 字段分割符 |
ARGC | 命令行参数个数 |
ARGV | 命令行参数数组 |
ARGIND | 命令行中当前文件的位置(从0开始算) |
FILENAME | 当前文件名 |
IGNORECASE | 是否忽略大小写 |
ERRNO | 最后一个系统错误的描述 |
CONVFMT | 转换格式(默认为%.6g) |
FIELDWIDTHS | 字符宽度列表 |
FNR | 各文件分别计数的行号 |
NF | 一条记录的字段的数目 |
NR | 已经读出的字段的数目 |
OFMT | 数字的输出格式(默认为%.6g) |
OFS | 输出字段分隔符 |
ORS | 输出记录分隔符 |
RLENGTH | 由match函数所匹配的字符串长度 |
RS | 记录分隔符 |
RSTART | 由match函数所匹配的第一个位置 |
SUBSEP | 数组下标分隔符 |
输出时以“ - ”符进行分隔:
linrm@linrm-VirtualBox:~$ awk '{print $1, $2, $3}' OFS=" - " file2.txt
101 - i - am
102 - thank - you!
103 - r - u
104 - year, - month,
查看每一行的字段数:
linrm@linrm-VirtualBox:~$ awk '{print "NF = " NF}' file2.txt # 或:awk '{printf "NF = %s\n", NF}' file2.txt
NF = 6
NF = 3
NF = 4
NF = 7
忽略大小写(网上是这么写的,但我试了下好像不行,难道哪里出错了?):
linrm@linrm-VirtualBox:~$ awk 'BEGIN{IGNORECASE=1} /thank/ {print $1, $2, $3}' file2.txt
6、支持正则表达式
输出包含字符串“ou”的行:
linrm@linrm-VirtualBox:~$ awk '/ou/' file2.txt # 输出包含"ou"的行
102 thank you!
104 year, month, day, hour, minute, second
linrm@linrm-VirtualBox:~$ awk '!/ou/' file2.txt # 输出不包含"ou"的行
101 i am a test file!
103 r u ok?
输出第2列包含字符“i”的行的第1、2、3列:
linrm@linrm-VirtualBox:~$ awk '$2 ~ /i/ {print $1, $2, $3}' file2.txt # ~表示匹配正则表达式
101 i am
linrm@linrm-VirtualBox:~$ awk '$2 !~ /i/ {print $1, $2, $3}' file2.txt # !~表示不匹配正则表达式
102 thank you!
103 r u
104 year, month,
7、字符串函数
函数 | 说明 |
---|---|
length() | 返回字符串的长度 |
index() | 返回下标 |
tolower() | 转换成小写并返回字符串 |
toupper() | 转换成大写并返回字符串 |
substr() | 返回字符串中的子串 |
match() | 返回下标,但它不搜索子串 |
sub() | 替换匹配的第一个字符串序列,并返回整个字符串 |
gsub() | 替换匹配的所有字符串序列,并返回整个字符串 |
split() | 分割字符串并将各部分放到使用整数下标的数组中 |
打印各行字符串的长度:
linrm@linrm-VirtualBox:~$ awk '{print length()}' file2.txt # 这里的“()”可省略
21
14
11
42
打印字符串长度超过20的行:
linrm@linrm-VirtualBox:~$ awk 'length>20' file2.txt
101 i am a test file!
104 year, month, day, hour, minute, second
字符串大小写转换:
linrm@linrm-VirtualBox:~$ awk '{print $1, tolower($2), toupper($3)}' file2.txt
101 i AM
102 thank YOU!
103 r U
104 year, MONTH,