内容简介:awk 是一种样式扫描和处理语言,使用 Linux 的 awk 命令可以高效快捷地进行文本处理。awk 扫描文本的每一行并执行指定的命令。awk 诞生于 1977 年,借鉴了 C 语言等编程语言,名字取自三位设计者 Alfred Aho、Peter Weinberger 和 Brian Kernighan 的姓氏。awk 的版本众多,本文中使用的是 Ubuntu 上的 GNU Awk,在 MacOS 上可以使用 HomeBrew 安装 gawk。awk 可以直接在命令行中执行,也可以编写
awk 是一种样式扫描和处理语言,使用 Linux 的 awk 命令可以高效快捷地进行文本处理。awk 扫描文本的每一行并执行指定的命令。
awk 诞生于 1977 年,借鉴了 C 语言等编程语言,名字取自三位设计者 Alfred Aho、Peter Weinberger 和 Brian Kernighan 的姓氏。awk 的版本众多,本文中使用的是 Ubuntu 上的 GNU Awk,在 MacOS 上可以使用 HomeBrew 安装 gawk。
用法
awk 可以直接在命令行中执行,也可以编写 .awk
后缀的文件然后执行。awk 以行为单位进行文本处理,对于接收到的每一行都会执行指定的行为。
命令行执行
$ awk [ -F fs ] [ -v var=value ] 'pattern {action}' [ file ... ]
复制代码
其中 -F
指定分隔符, -v
指定 awk 的内置变量。
例如对于 /etc/passwd
文件中的内容:
root:x:0:0:root:/root:/usr/bin/zsh 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 复制代码
如果要输出每一行的内容,可以使用
$ awk '{print $0}' /etc/passwd
复制代码
其中 $0
表示扫描到的文本行。
文件执行
.awk
文件可以分成三个部分来写,如下:
# passwd.awk
BEGIN{
FS="\n";
print "Before action";
}
{
print $0;
}
END{
print "After action";
}
复制代码
BEGIN 块用于定义处理每一行之前的行为,可以用来设置 awk 的内置变量,设置好后在后面处理每一行时都会生效。
END 块用于定义处理完文本之后的行为,可以用来输出一些总结信息。
BEGIN 和 END 中间的块是对于每一行的操作。直接在命令行中执行 awk 时也可以用 BEGIN 和 END 块。
写好文件后在命令行中执行:
Before action root:x:0:0:root:/root:/usr/bin/zsh 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 After action 复制代码
变量
$ + 数字
$0
表示扫描到的行, $1
表示将该行分隔后的第 1 项, $2
表示将该行分隔后的第 2 项,以此类推。
为了输出 /etc/passwd
的用户名(第一项),可以执行下面语句:
$ awk -F ':' '{print $1}' /etc/passwd
root
daemon
bin
sys
复制代码
这里以处理第一行 root:x:0:0:root:/root:/usr/bin/zsh
为例,awk 处理是会先按照 -F
设置的分隔符 :
将这行分割为 root x 0 0 root /root /usr/bin/zsh
然后输出第一项 root
特殊变量
-
FS(field separator)
FS 是输入字段分隔符,例如上面设置的
:,其默认值是空格,可以在命令行中使用-F设置,也可以在 BEGIN 块中通过FS=设置为某个字符串或者一个正则表达式。例如:$ awk -F ":" '{print $1,$2,$3}' /etc/passwd root x 0 daemon x 1 bin x 2 sys x 3 复制代码 -
OFS(output field separator)
OFS 是输出字段连接符,上面例子中的输出默认使用空格作为输出字段连接符,通过设置 OFS 变量进行修改:
$ awk -F ":" -v OFS="-" '{print $1,$2,$3}' /etc/passwd root-x-0 daemon-x-1 bin-x-2 sys-x-3 复制代码 -
RS(record separator)
前面提到的例子中,awk 都默认以行为单位处理文本,每一行保存了一条记录,这是因为默认的记录分隔符 RS 为 "\n"。还有一些文本在存储时并不是想 csv 等文件一样以行单位,例如:
# people.txt P1 male 15 p2 female 20 p3 male 19 复制代码
上面的文件中使用 "\n\n" 分隔记录,每个记录中又使用 "\n" 分隔字段,可以这样处理:
$ awk -F "\n" -v RS="\n\n" '{print $1,$2,$3}' people.txt P1 male 15 p2 female 20 p3 male 19 复制代码 -
ORS(output field separator)
与 RS 类似,ORS 设置输出的记录分隔符。
$ awk -F "\n" -v RS="\n\n" -v ORS="\n***\n" '{print $1,$2,$3}' people.txt P1 male 15 *** p2 female 20 *** p3 male 19 *** 复制代码 -
NR(number of records)
NR 表示当前正在处理的记录的是第几项,如果 NR 出现在 END 块中则表示已处理的记录数
$ awk -F ":" '{print "line" NR ":" $1,$2,$3}' /etc/passwd line1:root x 0 line2:daemon x 1 line3:bin x 2 line4:sys x 3 复制代码如果同时处理多个文件,那么这个项数会累加
$ awk -F ":" '{print "record" NR ":" $1,$2,$3}' people.txt /etc/passwd record1:P1 record2:male record3:15 record4: record5:p2 record6:female record7:20 record8: record9:p3 record10:male record11:19 record12:root x 0 record13:daemon x 1 record14:bin x 2 record15:sys x 3 复制代码 -
NF(number of fields)
NF 表示一条记录中分隔后的字段数,因此这个值与设置的 FS 有关:
# 以 ":" 为分隔符 $ awk -F ":" '{print "record" NR " with " NF " fields:" $1,$2,$3}' /etc/passwd record1 with 7 fields:root x 0 record2 with 7 fields:daemon x 1 record3 with 7 fields:bin x 2 record4 with 7 fields:sys x 3 # 以 "o" 为分隔符 $ awk -F "o" '{print "record" NR " with " NF " fields:" $1,$2,$3}' /etc/passwd record1 with 7 fields:r t:x:0:0:r record2 with 5 fields:daem n:x:1:1:daem n:/usr/sbin:/usr/sbin/n record3 with 3 fields:bin:x:2:2:bin:/bin:/usr/sbin/n l gin record4 with 3 fields:sys:x:3:3:sys:/dev:/usr/sbin/n l gin 复制代码 -
FILENAME
FILENAME 是当前正在处理的文件的名字
$ awk -F ":" '{print FILENAME}' /etc/passwd people.txt /etc/passwd /etc/passwd /etc/passwd /etc/passwd people.txt people.txt people.txt people.txt people.txt people.txt people.txt people.txt people.txt people.txt people.txt 复制代码这个值在开始处理记录后才有意义,因此在 BEGIN 块中尝试输出 FILENAME 将得到空值
-
FNR
前面的 NR 表示的项数在处理多个文件时会累加,而FNR 表示记录位于当前文件的第几项
awk -F ":" '{print "record" FNR ":" $1,$2,$3}' people.txt /etc/passwd record1:P1 record2:male record3:15 record4: record5:p2 record6:female record7:20 record8: record9:p3 record10:male record11:19 record1:root x 0 record2:daemon x 1 record3:bin x 2 record4:sys x 3 复制代码
内置函数
awk 提供了一些内置函数,便于文本和运算的处理,包括获取字符串长度的 length()
,获取随机数的 rand()
,计算正余弦的 sin()
和 cos()
。
这些函数可以在官方手册中查询。
记录筛选
上面的所有的例子都对每一条记录进行了操作,事实上还可以用条件进行筛选。
正则判断
使用正则表达式可以对记录进行模式匹配:
$ awk -F ':' '/root/ {print $1,$2,$3}' /etc/passwd
root x 0
复制代码
这里筛选出了包含 root
的记录。
条件判断
结合 awk 的内置变量和函数也可以进行筛选:
# 输出第一个字段长度大于 2 且在 第 1 条记录之后的记录
$ awk -F ':' 'length($1)>3 && NR>1 {print $0}' /etc/passwd
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
复制代码
if 语句
awk 也提供了 if 语句:
# 输出第 3 个字段为 0 的记录
$ awk -F ':' '{if ($3==0)print $0}' /etc/passwd
root:x:0:0:root:/root:/usr/bin/zsh
复制代码
awk 还有 for 语句,与 C 语言中形式类似:
$ awk -v ORS="," 'BEGIN{ for(i=1;i<5;i++) print i}'
1,2,3,4,
复制代码
字符与数字
awk 提供了对数学运算符和逻辑运算符的支持的支持,在 awk 中字符串与数字间还可以直接进行强制类型转换, +0
可以强制转换为数字,与空格拼接可以转换为字符串:
awk 'BEGIN{print "origin\tnumber\tstring"}{print $0,"\t",$0+0,"\t",$0 ""}' people.txt
origin number string
P1 0 P1
male 0 male
15 15 15
0
p2 0 p2
female 0 female
20 20 20
0
p3 0 p3
male 0 male
19 19 1
复制代码
这里使用了 $0 ""
的表示方式将原记录与空格进行了拼接,但在某些情况下会出现问题,考虑下面的语句:
$ awk 'BEGIN { print -12 " " -24 }'
-| -12-24
复制代码
这里想要在 -12 和 -24 中间加一个空格,但没有得到想要的结果,这是由于数学运算符的优先级高于拼接操作,所以解析顺序如下:
-12 (" " - 24)
⇒ -12 (0 - 24)
⇒ -12 (-24)
⇒ -12-24
复制代码
要得到正确的正确的结果需要使用括号结合:
$ awk 'BEGIN { print -12 " " (-24) }'
-| -12 -24
复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Web Designer's Idea Book
Patrick Mcneil / How / 2008-10-6 / USD 25.00
The Web Designer's Idea Book includes more than 700 websites arranged thematically, so you can find inspiration for layout, color, style and more. Author Patrick McNeil has cataloged more than 5,000 s......一起来看看 《The Web Designer's Idea Book》 这本书的介绍吧!