Mais conteúdo relacionado 6, awk3. 概述
• 什么是awk? awk最初是unix上用于处理特定
格式文本的一门编程语言, 后来被移植到
linux. 除了最初的awk版本, 还有nawk在原有
的版本上做了一些改进, gawk则是awk的
GNU实现, 目前linux上使用的是gawk.
• awk在很多方面都与sed类似, 如下:
1, 输入: 标准输入, 文本文件, 管道;
2, 语法元素: 正则表达式, 行范围, 命令;
3, 处理方式: 逐行处理.
4. 如何工作?
• 首先介绍一下awk通常处理的文本格式: 文件的每一行都由多个
字段组成, 每个字段之间使用一个或者多个空白字符分开. 类似:
Mary 28 IT QA 10000
John 30 IT Development 15000
Mayer 50 IT Manager 30000
• awk的工作过程
1, 读取输入的一行(被称为一条记录), 并将这一行赋值给内部变
量$0;
2, 判定当前行是否符合过滤条件(模式, 范围, 条件判断). 如果为
否, 则跳过当前行处理下一行;
3, 根据字段(Field)分隔符(Field Separator)的设置对记录进行分割,
分隔符由变量FS指定默认为空格(包括制表符和空格符). 分割之
后按照字段的顺序依次赋值给内部变量$1, $2, $3......比如第一条
记录的第一个字段是Mary.
4, 执行指定的操作, 比如格式化输出某些字段;
5, 清空内部记录和字段变量($0, $1, $2...), 处理下一行.
5. 语法格式
• awk命令使用如下语法格式:
awk ‘condition’ file1 file2...
awk ‘action’ file1 file2...
awk ‘condition action’ file1 file2...
其中condition表示过滤条件, 只有符合该过滤条件才执行动作.
condition可以是:
1), 模式, 比如: /^Mary/;
2), 模式范围, 比如: /^Mary/,/John$/
3),比较表达式, 比如: $3 > 4000
action表示对当前记录或者某些字段执行的操作, 使用{}进行包
含; 如果没有写action则默认打印该行.
• 示例:
awk ‘/^Mary/,print $2-’ emp # 打印以Mary开头的记录的
第二个字段
ps -ef | awk ‘/^root /,print $2-‘ # 打印root用户所有进程的pid
6. 输出
- print函数
• awk提供了print函数支持基本的打印功能, 用法如下:
1, 不提供仸何参数, 默认打印当前行$0;
2, 指定参数, 多个参数使用逗号分隔; print会依次打
印这些参数, 每个参数使用变量OFS指定的变量分开,
默认OFS是空格; 如果参数之间不使用逗号分开, 那
么这些参数打印时会连接在一起.
print函数中可以使用$0, $1, $2...引用当前的记录或者
字段.
• 示例:
date | awk '{print "Month: " $2 "nYear: ",$6-‘
输出如下格式:
Month: Jan
Year: 2013
7. 输出
- print函数
• 转义字符
print函数支持如下常用的转义字符:
t 制表符 n 换行
r 回车 b 退格
f 换页
示例:
awk '/^John/{print "ttHave a nice day, " $1, $2 "!"}' emp
输出如下:
Have a nice day, John Mayer!
8. 输出
- 内置变量
• 与print函数相关的内置变量有:
OFS 输出多个参数时, 指定参数之间的分隔符,
默认为空格. 通过如下方式修改:
awk 'BEGIN,OFS="|"-......’ filename
示例:
awk 'BEGIN{OFS="|"}{print $2,$3, $6}' emp
OFMT 打印浮点数字时, 指定数字的格式, 示例:
# 仅打印小数点后的两位, 作四舍五入
awk 'BEGIN,OFMT="%.2f"; print 1.24565-‘
注意: OFS/OFMT变量基本上只有在使用print函数时
才会进行设置, 后面的printf函数无需设置这些变量.
9. 格式化输出
- printf
• printf函数用于格式化输出, 参数由格式控制串和其
他的值表达式组成, 示例:
printf(“He is %d years oldn”, 15);
格式控制串: “He is %d years old”
值表达式: 15
printf在打印输出时, 会使用表达式的值代替相应位
置的格式占位符(以%字符开头), 比如这里使用第一
个表达式的值15代替第一个格式占位符%d.
• 与print不同的是printf函数不会自动换行, 因此如果
需要换行则需要在格式控制串末尾加上n字符;
10. 格式化输出
- 格式占位符
• printf的格式占位符支持如下类型:
c 字符 s 字符串
d 十进制整数 ld 十进制长整数
u 十进制无符号整数
lu 十进制无符号长整数 x 十六进制整数
lx 十六进制长整数 o 八进制整数
lo 八进制长整数 f 浮点数
e 科学计数法表示的浮点数
g 选用e或f中较短的一种形式
• 格式占位符可以指定某些修饰符, 比如对齐方式,
- 左对齐 # 显示8进制前面加0, 16进制加0x
+ 使用d,e,f,g转换整数时加上正号+或者负号-
0 指定长度时, 使用0而不是空格进行填充
• 示例:
echo "linux" | awk '{printf "|%-15s|n", $1-‘
# 输出: |linux |
awk 'BEGIN{printf "%.2fn",1.2363-‘
# 输出浮点数, 仅保留两位小数
11. 过滤条件
• awk使用过滤条件来决定是否对当前记录执行操作, 过滤条件分为模式,
模式范围或者比较表达式, 可以使用逻辑操作符&&/||对它们进行组合:
1, 模式
只有匹配某个模式的行才执行给定的操作, 示例:
awk ‘/^Mary/,print $2-’ emp # 打印匹配^Mary的行
2, 模式范围
通过指定一个模式范围, 表示仅对该范围内的记录进行操作, 示例:
# 打印匹配Mary到匹配John记录的第五个字段
awk '/Mary/,/John/{print $5}' emp
3,比较表达式
可以通过指定某个比较表达式来决定是否对记录执行操作, 示例:
awk ‘$3>=30,print $5-’ emp # 仅当第三个字段>=30执行操作
awk还提供了模式匹配操作符~(匹配)/!~(不匹配), 示例:
awk ‘$1 ~ /John/,print-’ emp # 如果第一个字段匹配John则打印
• 可以使用逻辑操作符&&/||对这些过滤条件进行组合, 示例:
awk ‘/John/ && $3<50 ,print-’ emp # 匹配模式John并且第三个字段
小于50
12. 比较表达式
• awk的比较表达式支持所有的关系运算符, 并提供了
特有的模式匹配运算符, 如下:
< 小于 <= 小于或等于
== 等于 != 不等于
>= 大于或等于 > 大于
~ 匹配模式 !~ 不匹配模式
示例:
awk '$3==30{print $1,$2}' emp
awk '$6<20000{print $1,$2}' emp
awk '$1 ~ /John/{print $1,$2}' emp
• 比较表达式可以使用在过滤条件部分, 也可以写在
操作部分, 示例:
awk '$1 ~ /John/{if($3>25){print $1,$2;}}' emp
13. 范围
• 过滤条件可以指定为某个范围, 只有符合该
范围的记录才执行操作. 范围可以由模式指
定, 或者由条件表达式指定, 或者是两者的组
合. 示例:
awk ‘NR==1, NR==5’ emp # 打印第一到第五条记录
awk ‘NR==1, /^John/’ emp # 打印第一条记录到匹配
以John开头的记录
awk ‘/^Mary/, /^John/’ emp # 打印匹配以Mary开头的
记录到以John开头的记录
14. 算数运算
• awk支持如下算数运算:
+ 加 - 减
* 乘 / 除
% 求余 ^ 幂
示例:
awk '$3*3 > 100{print $1,$2}' emp
• 算数运算可以使用在条件部分也可以使用在操
作部分, 示例:
awk '$1 ~ /John/{printf "per year: %dn", $6*12}' emp
15. 逻辑操作符
• awk逻辑操作符包括: 逻辑与(&&), 逻辑或
(||), 逻辑非(!). 示例:
awk '$1 ~ /John/ && $3>20{print $1, $2}' emp
• 逻辑操作也可以写在操作部分, 示例:
awk '$1 ~ /John/{if($3>25 && $6>10000)print}' emp
16. 变量
• awk允许自定义变量, 变量不需要指定类型,
变量的值可以是字符串或者数字. 如果变量
没有被初始化, 那么会根据情况初始化为空
字符串或者数字0. 变量可以通过下面的方
式定义:
1, 命令行指定
使用-v选项指定一个变量, 示例:
awk -v var="abc" 'BEGIN{print var-‘
2, 在操作块中定义变量, 示例:
awk 'BEGIN{a=1;print a;}'
17. 变量
- 操作
• awk允许对变量作如下赋值操作:
= 赋值 示例: a=5,s=“abc”
+= a+=5 等价于 a=a+5
-= a-=5 等价于 a=a-5
*= a*=5 等价于 a=a*5
/= a/=5 等价于 a=a/5
%= a%=5 等价于 a=a%5
^= a^=5 等价于 a=a^5
• 自增++, 自减--
对变量进行自增或者自减操作, 示例:
awk ‘BEGIN,a=5;a++; print a;-’ # 输出: 6
自增/自减操作符可以放在变量前后, 两者的结果不同. 放在前面
先自增, 然后返回值. 放在后面则先返回值, 后自增. 示例:
awk ‘BEGIN,a=5; b=++a;c=a++;print a,b,c;-’ # 输出7 6 6
18. 内置变量
• awk将每读入的一行作为一条记录($0), 每条记录中使用字段分隔符(FS)
分开的字符串作为一个字段($1, $2...). awk有如下内置变量是与它们相
关的:
RS 记录分隔符, 默认是n
ORS 输出记录分隔符, 默认是n
NR 当前的记录号, 从1开始
FNR 记录在当前文件的号码, 每读取一个文件FNR置1
NF 当前记录的字段数
FS 字段分隔符, 默认为空格字符, 通过如下方式修改FS:
1, awk命令的-F选项, 示例:
awk -F: # 使用:作为FS
awk -F’* :+’ # 使用空格或者:作为FS
2, 使用BEGIN块对FS赋值, 示例:
awk ‘BEGIN,FS=":"-......’
OFS 输出字段分隔符, 当使用print打印多个使用逗号分开的参
数时, OFS在每打印一个参数之后被打印. OFS默认为空格.
FILENAME 用于处理的文件的名称
19. 内置变量
NR & FNR
• 引用awk文档的解释:
NR ordinal number of the current record
FNR ordinal number of the current record in the current file
NR指的是当前的记录号, 不管出自哪个文件一直递增;
FNR指的是在当前文件中的记录号, 每读取一个新的文件
FNR重置为1. 示例:
echo "1 abc" > file1
echo "2 def" > file2
awk 'BEGIN{print "NRtFNRtContent"}{printf "%dt%dt%sn", NR,
FNR, $0}' file1 file2
输出如下:
NR FNR Content
1 1 1 abc
2 1 2 def
20. BEGIN/END操作块
• awk允许在对文件进行操作之前或者操作完成之后
执行指定的动作, 这是通过BEGIN/END操作块来实现
的. 其中BEGIN的操作在处理文件之前发生, END的操
作则在文件处理完成之后发生. 示例:
awk 'BEGIN{print "Begin..."}{print $1}END{print "End..."}' emp
首先在打印文件所有记录的第一个字段之前输
出”Begin...”, 完成文件的操作之后打印”End...”
• BEGIN块通常用于做一些初始化的工作, 比如定义变
量; END块则常用于做一些总结性的输出. 示例:
awk 'BEGIN{count=0}/^Mary/{count++}END{print "Mary found
"count" times"}' emp
BEGIN块可以独立存在, 即可以没有操作块和输入文
件等. 示例:
awk ‘BEGIN,print “Hello AWK”-’ # 打印Hello AWK
21. 输出重定向
• 默认情况下print/printf函数均输出到标准输
出, 可以使用操作符>将输出重定向到指定
的文件. 示例:
awk '{print $1, $3 > "file"}' emp
将第一/三字段重定向到file文件中, 会覆盖
之前已有的内容.
• 使用>>对文件进行追加, 与>的区别在于>在
第一次写的时候会清除文件已有内容, 而>>
不会; 之后的写入操作都是追加.
22. system函数
• awk函数system可以用于调用linux系统命令,
该命令可以是shell内置命令也可以是二进制
程序, 示例:
awk 'BEGIN{system("echo Hello AWK")-‘
awk ‘BEGIN,system(“ls -l")-‘
• 可以一次调用多个命令, 命令之间使用分号;
分隔, 示例:
awk 'BEGIN{system("echo Hello AWK;echo $?;ls")}'
23. 条件语句
• awk支持条件判断语句, 语法格式与c语言相同,
如下:
if(...) {...}
if(...) {...} else {...}
if(...) {...} else if(...) {...} else {...}
• 示例:
awk ',if($3>=30)print $1, “too high”-' emp
awk ',if($3>=30),print $1, “too high”- else ,print
$1, “normal”--' emp
24. 循环语句
• awk支持如下循环语句:
while循环
do...while循环
for循环
• 示例:
awk '{i=1;while(i<=NF){print i, $i;i++}}' emp
awk '{for(i=1;i<=NF;i++){print i, $i}}' emp
说明: i=1; $i表示第1个字段 $NF表示最后一个
字段.
• 循环控制break/continue
用法与c语言中的break/continue语句相同.
25. next, exit
• next
next语句表示完成当前记录的操作, 处理下一
条记录, 示例:
# 如果第一个字段匹配Mary开头, 跳过该行处
理下一行
awk '{if($1~/^Mary/){next}print NR, $0}' emp
• exit
退出当前命令, 可以指定一个0-255之间的退出
状态, 0表示成功, 非0失败.示例:
awk '{if($3 > 45){exit 1}print NR, $0}' emp
26. 数组
• awk支持数组数据类型, 但是与普通的数组有所不同. awk的数组是关联
数组, 数组的下表可以是任意的数字和字符串. 与变量一样, 数组不需
要进行声明. 示例:
awk '{name[x++]=$2};END{for(i=0;i<NR;i++)print i, name[i]}' emp
说明: 使用数组记录第二个字段的值. END块用于打印数组的内容.
• 因为是关联数组, 不能够向普通的数组一样使用索引进行遍历, awk提
供了如下的方式遍历数组:
for(item in array) {
print array[item]
}
示例:
awk '/^John/{name[NR]=$1};END{for(i in name)print name[i]}' emp
注意: 使用这种方式遍历数组时并不能保证按照数组元素的插入顺序
进行访问.
• 使用字符串作为数组下标, 示例:
awk ‘,count*$2+++-;END,for(name in count)print name, count*name+-’
emp # 输出
Brown 1
Mayer 3
Black 2
27. 数组
- split & delete
• split函数用于对字符串进行拆分, 并将拆分
后的各项存储在数组中. 示例:
awk 'BEGIN{split("3/15/2004", date, "/");print "The month is
" date[1] " and the year is " date[3]} '
对字符串”3/15/2004”分解得到数组date.
• delete函数用于删除数组的元素, 示例:
awk ‘,line*x+++=$2-END,for(x in line)delete line*x+-’ emp
28. 内置函数
- 字符串函数
• awk提供了一些用于文本处理的函数, 列举如下:
sub(pattern, replacement)
sub(pattern, replacement, target) 示例:
# 替换$0中第一个匹配Mary的为Maria
awk '{sub(/Mary/, "Maria"); print}' emp
# 替换$1中第一个匹配Mary的为Maria
awk ',sub(/Mary/, "Maria“, $1); print-' emp
gsub(pattern, replacement)
gsub(pattern, replacement, target)
与sub不同的是, gsub会进行全局替换
index(string, substring)
index函数用于查找子字符串在父串中第一次出现的位置, 不支
持使用正则表达式. 位置从1开始, 如果未出现返回0. 示例:
echo "abcdefg" | awk '{print index($1, "abc")-’ # 1
29. 内置函数
- 字符串函数
length(string)
返回字符串长度, 示例:
awk 'BEGIN{print length("abc")-‘
substr(string, start)
substr(string, start, size)
截取字符串, 如果超出了字符串的长度范围返回实际的字串, 示例:
# 返回World
awk 'BEGIN{print substr("Hello World",7,10)-‘
match(string, pattern)
返回模式在字符串中首次出现的位置, 示例:
awk 'BEGIN{start=match("Good, TED", /[A-Z++$/); print start-‘
awk还提供了内部变量RSTART/RLENGHT分别用于保存模式匹配的信息,
RSTART表示模式的起始位置, RLENGHT表示模式匹配到字符串的长度.
如果没有匹配函数返回值为0, RSTSART设置为0. 示例:
awk 'BEGIN{s="Good, TED";start=match(s, /[A-Z]+$/); if(start>0)print
substr(s,RSTART,RLENGTH)}'
30. 内置函数
- 字符串函数
split(string, array, separator)
split(string, array)
split用于将字符串分割为数组, 可以指定分隔符,
若不指定默认内置变量FS为分隔符. 示例:
awk 'BEGIN,split("12/25/2001", date, "/"); print date*2+-‘
sprintf(format, expr1, expr2...)
与printf相同的是, sprintf用于格式化字符串, 但
是它不会将格式化之后的字符串打印到标准输
出而是返回. 示例:
awk 'BEGIN{s=sprintf("Name: %-10s Age: %-3d", "Ted",
"27");print s}'
31. 内置函数
- 算数函数
• awk提供了如下算数函数:
int(x) 对x进行取整
rand() 返回0-1之间的随机数
srand(x) 设置x为随机数的新种子
sqrt(x) x平方根
sin(x) 正弦函数
cos(x) 余弦函数
log(x) x自然对数(底数e)
exp(x) x的e指数函数
32. 内置函数
- 时间函数
• awk提供了如下两个时间函数:
1, systime函数返回自1970/1/1开始经过的时间(按秒计算). 示例:
awk 'BEGIN{print systime();}' # 1358479710
2, strftime函数对时间戳进行格式化, 如果不指定时间戳则使用
当前的时间, 语法如下:
strftime() 返回按照默认格式的当前时间
strftime(format) 按照指定格式格式化当前时间
strftime(format, timestamp) 按照指定的格式格式化
指定的时间戳
示例:
awk 'BEGIN{print strftime();}' # Fri Jan 18 11:33:46 CST 2013
awk 'BEGIN{print strftime("%D");}' # 01/18/13
awk 'BEGIN{print strftime("%T");}' # 11:35:09
awk 'BEGIN{print strftime("%T", systime());}' # 11:36:29
33. 内置函数
- 时间函数
strftime支持的格式说明:
%D 采用mm/dd/yy格式表示的日期
%T 采用HH/MM/SS格式表示的时间
%m 月 %d 日 %y 年, 比如04
%Y 年, 比如2004
%H 小时24 %I 小时12
%M 分钟 %S 秒
%b 月Jan %B 月January
%a 星期Sun %A 星期Sunday
示例:
awk 'BEGIN{print strftime("%Y-%m-%d %H-%M-%S",
systime());-‘
输出: 2013-01-18 11-45-32
34. 命令行选项
• awk支持如下常用的选项:
-v 定义变量, 示例:
awk -v var="abc" 'BEGIN{print var-‘
-F 设置FS的值
-f 执行awk脚本文件
--version打印awk的版本信息
Notas do Editor 说明:linux上面使用的/bin/awk命令实际是指向/bin/gawk的符号链接. awk内置变量: 指的是由awk命令使用的变量, 比如$0, $1, FS, OFS等. OFS: output field separator