前言:使用awk作为文本处理工具,正则表达式是少不了的。 要掌握这个工具的正则表达式使用。其实,我们不必单独去学习它的正则表达式。正则表达式就像一门程序语言,有自己语法规则已经表示意思。 对于不同工具,其实大部分表示意思相同的。在linux众多文本处理工具(awk,sed,grep,perl)里面用到正则表达式。其实就只有3种类 型。详细可以参考:linux shell 正则表达式(BREs,EREs,PREs)差异比较 。只要是某些工具是属于某种类型的正则表达式。那么它的语法规则基本一样。 通过那篇文章,我们知道awk的正则表达式,是属于:扩展的正则表达式(Extended Regular Expression 又叫 Extended RegEx 简称 EREs)。
一、awk Extended Regular Expression (ERES)基础表达式符号介绍
字符 | 功能 |
---|---|
+ | 指定如果一个或多个字符或扩展正则表达式的具体值(在 +(加号)前)在这个字符串中,则字符串匹配。命令行: awk '/smith+ern/' testfile 将包含字符 smit,后跟一个或多个 h 字符,并以字符 ern 结束的字符串的任何记录打印至标准输出。此示例中的输出是: smithern, harry smithhern, anne |
? | 指定如果零个或一个字符或扩展正则表达式的具体值(在 ?(问号)之前)在字符串中,则字符串匹配。命令行: awk '/smith?/' testfile 将包含字符 smit,后跟零个或一个 h 字符的实例的所有记录打印至标准输出。此示例中的输出是: smith, alan smithern, harry smithhern, anne smitters, alexis |
| | 指定如果以 |(垂直线)隔开的字符串的任何一个在字符串中,则字符串匹配。命令行: awk '/allen | alan /' testfile 将包含字符串 allen 或 alan 的所有记录打印至标准输出。此示例中的输出是: smiley, allen smith, alan |
( ) | 在正则表达式中将字符串组合在一起。命令行: awk '/a(ll)?(nn)?e/' testfile 将具有字符串 ae 或 alle 或 anne 或 allnne 的所有记录打印至标准输出。此示例中的输出是: smiley, allen smithhern, anne |
{m} | 指定如果正好有 m 个模式的具体值位于字符串中,则字符串匹配。命令行: awk '/l{2}/' testfile 打印至标准输出 smiley, allen |
{m,} | 指定如果至少 m 个模式的具体值在字符串中,则字符串匹配。命令行: awk '/t{2,}/' testfile 打印至标准输出: smitters, alexis |
{m, n} | 指定如果 m 和 n 之间(包含的 m 和 n)个模式的具体值在字符串中(其中m <= n),则字符串匹配。命令行: awk '/er{1, 2}/' testfile 打印至标准输出: smithern, harry smithern, anne smitters, alexis |
[String] | 指定正则表达式与方括号内 String 变量指定的任何字符匹配。命令行: awk '/sm[a-h]/' testfile 将具有 sm 后跟以字母顺序从 a 到 h 排列的任何字符的所有记录打印至标准输出。此示例的输出是: smawley, andy |
[^ String] | 在 [ ](方括号)和在指定字符串开头的 ^ (插入记号) 指明正则表达式与方括号内的任何字符不匹配。这样,命令行: awk '/sm[^a-h]/' testfile 打印至标准输出: smiley, allen smith, alan smithern, harry smithhern, anne smitters, alexis |
~,!~ | 表示指定变量与正则表达式匹配(代字号)或不匹配(代字号、感叹号)的条件语句。命令行: awk '$1 ~ /n/' testfile 将第一个字段包含字符 n 的所有记录打印至标准输出。此示例中的输出是: smithern, harry smithhern, anne |
^ | 指定字段或记录的开头。命令行: awk '$2 ~ /^h/' testfile 将把字符 h 作为第二个字段的第一个字符的所有记录打印至标准输出。此示例中的输出是: smithern, harry |
$ | 指定字段或记录的末尾。命令行: awk '$2 ~ /y$/' testfile 将把字符 y 作为第二个字段的最后一个字符的所有记录打印至标准输出。此示例中的输出是: smawley, andy smithern, harry |
. (句号) | 表示除了在空白末尾的终端换行字符以外的任何一个字符。命令行: awk '/a..e/' testfile 将具有以两个字符隔开的字符 a 和 e 的所有记录打印至标准输出。此示例中的输出是: smawley, andy smiley, allen smithhern, anne |
*(星号) | 表示零个或更多的任意字符。命令行: awk '/a.*e/' testfile 将具有以零个或更多字符隔开的字符 a 和 e 的所有记录打印至标准输出。此示例中的输出是: smawley, andy smiley, allen smithhern, anne smitters, alexis |
\ (反斜杠) | 转义字符。当位于在扩展正则表达式中具有特殊含义的任何字符之前时,转义字符除去该字符的任何特殊含义。例如,命令行: /a\/\// 将与模式 a // 匹配,因为反斜杠否定斜杠作为正则表达式定界符的通常含义。要将反斜杠本身指定为字符,则使用双反斜杠。有关反斜杠及其使用的更多信息,请参阅以下关于转义序列的内容。 |
与PERs相比,主要是一些结合类型表示符没有了:包括:”\d,\D,\s,\S,\t,\v,\n,\f,\r”其它功能基本一样的。 我们常见的软件:javascript,.net,java支持的正则表达式,基本上是:EPRs类型。
二、awk 常见调用正则表达式方法
- awk语句中:
awk ‘/REG/{action}’
/REG/为正则表达式,可以将$0中,满足条件记录 送入到:action进行处理.
- awk正则运算语句(~,~!等同!~)
[chengmo@centos5 ~]$ awk 'BEGIN{info="this is a test";if( info ~ /test/){print "ok"}}'
ok
- awk内置使用正则表达式函数
gsub( Ere, Repl, [ In ] )
sub( Ere, Repl, [ In ] )
match( String, Ere )
split( String, A, [Ere] )
详细函数使用,可以参照:linux awk 内置函数详细介绍(实例)
通过上面细述,不知道大家有没有对awk正则表达式有一个更加清楚的认识。 有什么问题可以与我交流!
awk用-F指定多分隔符及正则表达式
命令行选项 -F"[@ /t]" 告诉awk @, 空格和Tab都是字段分隔符,例如:
awk -F"[@ /t]" '{print $2,$3}' test
以@,空格,Tab键分割test文件的每一行,并输出第二、第三列。
awk '$2~/^(126|yahoo)/{print $2, $3}' test
如果改行的第二个字段以"123"或"yahoo"开始,则输出改行的第二、第三列。
awk '$1~/[0-9][0-9]$/{print $1, $3}' test
如果改行的最后两个字段以数字结束,则输出改行的第一、第三列。
awk '/mail/{print $0}' test
输出test文件中含有"mail"字符串的行
$awk '$2~/mail/{print $0}' test
输出test文件中第二个字段含有"mail"字符串的行
$awk '$2 == "gmail.com"{$1 = "ggg";print}' test
输出test文件中第二个字段是"gmail.com"的行,并把改行第一列改为"ggg"
awk '$2 == "gmail.com"{$1 = "ggg"}{print}' test
输出test文件中所有行,并且如果第二个字段是"gmail.com",把改行第一列改为"ggg"
awk '{IGNORECASE=1;if($2 ~/^[a-z]/&& $2~/net$/){print $0}}' test
打开test文件,忽略字母大小写,如果第二字段以[a-z]开头,并以"net"结尾,则输出该行。
AWK记录、字段、模式、跨平台移植及正则表达式 2014-06-02 20:39:20
分类: Linux
1,
记录分隔符:默认行输入和输出的分隔符都是回车,保存在RS和ORS内部变量中。变量$0:awk每次一行取得整条记录,$0随之改变,同时内部变量NF(字段的总数)也随之变化。变量NR:每条记录的行号,处理完一行将会加1,所以全部处理完后可以理解成行数的总数。
2,
FS: Field Separator
OFS: Output Field Separator
RS: Row Separator (行分隔符)
ORS: Output Row Separator
NF: Number of Fields
NR: Number of Rows
正在处理的哪一行就变成了$0
3,
[root@rhel helinbash]# gawk '{print NR,"--> ",$0}' /etc/passwd
1 --> root:x:0:0:root:/root:/bin/bash
2 --> bin:x:1:1:bin:/bin:/sbin/nologin
3 --> daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 --> adm:x:3:4:adm:/var/adm:/sbin/nologin
5 --> lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 --> sync:x:5:0:sync:/sbin:/bin/sync
7 --> shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8 --> halt:x:7:0:halt:/sbin:/sbin/halt
9 --> mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10 --> news:x:9:13:news:/etc/news:
11 --> uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
12 --> operator:x:11:0:operator:/root:/sbin/nologin
13 --> games:x:12:100:games:/usr/games:/sbin/nologin
14 --> gopher:x:13:30:gopher:/var/gopher:/sbin/nologin
15 --> ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
16 --> nobody:x:99:99:Nobody:/:/sbin/nologin
17 --> nscd:x:28:28:NSCD Daemon:/:/sbin/nologin
18 --> vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin
19 --> rpc:x:32:32:Portmapper RPC user:/:/sbin/nologin
20 --> mailnull:x:47:47::/var/spool/mqueue:/sbin/nologin
21 --> smmsp:x:51:51::/var/spool/mqueue:/sbin/nologin
22 --> pcap:x:77:77::/var/arpwatch:/sbin/nologin
23 --> ntp:x:38:38::/etc/ntp:/sbin/nologin
24 --> dbus:x:81:81:System message bus:/:/sbin/nologin
25 --> avahi:x:70:70:Avahi daemon:/:/sbin/nologin
26 --> sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
27 --> rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin
28 --> nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
29 --> haldaemon:x:68:68:HAL daemon:/:/sbin/nologin
30 --> avahi-autoipd:x:100:101:avahi-autoipd:/var/lib/avahi-autoipd:/sbin/nologin
31 --> xfs:x:43:43:X Font Server:/etc/X11/fs:/sbin/nologin
32 --> gdm:x:42:42::/var/gdm:/sbin/nologin
33 --> sabayon:x:86:86:Sabayon user:/home/sabayon:/sbin/nologin
34 --> oracle:x:500:500::/home/oracle:/bin/bash
35 --> named:x:25:25:Named:/var/named:/sbin/nologin
[root@rhel helinbash]#
4,
[root@rhel helinbash]# gawk '{print NR,"--> ",$1}' names.txt
1 --> Tom
2 --> Molly
3 --> John
4 --> yang
[root@rhel helinbash]# gawk '{print NR,":",NF,"--> ",$1}' names.txt
1 : 3 --> Tom
2 : 3 --> Molly
3 : 3 --> John
4 : 3 --> yang
[root@rhel helinbash]#
5,
[root@rhel helinbash]# vim names.txt
[root@rhel helinbash]# gawk '{print NR,":",NF,"--> ",$1}' names.txt
1 : 3 --> Tom
2 : 3 --> Molly
3 : 3 --> John
4 : 4 --> yang
[root@rhel helinbash]# cat names.txt
Tom Savage 100
Molly Lee 200
John Doe 300
yang wawa asdfas -121212
[root@rhel helinbash]#
[root@rhel helinbash]# cat names.txt
Tom Savage 100
Molly Lee 200
John Doe 300
yang wawa asdfas -121212
[root@rhel helinbash]#
6,
[root@rhel helinbash]# gawk '{print $1,$NF}' names.txt
Tom 100
Molly 200
John 300
yang -121212
[root@rhel helinbash]#
二,跨平台数据移植格式转换
1,
把linux文本转化为window文本
[root@rhel helinbash]# gawk '{ORS="\r\n";RS="\n";print $0}' names.txt > names.win
[root@rhel helinbash]# cat names.win
Tom Savage 100
Molly Lee 200
John Doe 300
yang wawa asdfas -121212
2,
把window文本转化为linux版本
[root@rhel helinbash]# gawk '{ORS="\n";RS="\r\n";print $0}' names.win > names.linux
[root@rhel helinbash]# cat names.linux
Tom Savage 100
Molly Lee 200
John Doe 300
yang wawa asdfas -121212
[root@rhel helinbash]#
三,模式
1,
awk模式用来控制输入的文本行执行什么样的操作
模式为正则表达式
模式具有着隐式if语句
模式写在模式操作符两个“//”中
2,
[root@rhel helinbash]# gawk '/^root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@rhel helinbash]#
3,
操作
格式
模式{操作语句1;操作语句2;....;}
或者
模式
{
操作语句1
操作语句2
........
}
4,
模式对单列处理
[root@rhel helinbash]# gawk -F: '/bash$/{ print $1}' /etc/passwd
root
oracle
[root@rhel helinbash]# gawk -F: '$7 ~ /bash$/{ print $1}' /etc/passwd
root
oracle
[root@rhel helinbash]#
[root@rhel helinbash]# gawk -F: '$7 !~ /bash$/{ print $1}' /etc/passwd
bin
daemon
adm
lp
sync
shutdown
halt
news
uucp
operator
games
gopher
ftp
nobody
nscd
vcsa
rpc
mailnull
smmsp
pcap
ntp
dbus
avahi
sshd
rpcuser
nfsnobody
haldaemon
avahi-autoipd
xfs
gdm
sabayon
named
[root@rhel helinbash]#
四,正则表达式
1,
很多地方都是用到正则表达式来匹配特定的信息
^ 串首
$ 串尾
. 匹配单个任意字符
* 匹配零个或多个前面的字符
+ 匹配一个或多个前面的字符
? 匹配零个或一个前面的字符
[ABC] 匹配括号中给出的任一个字符
[A-Z] 匹配A到Z之间的任一个字符
A|B 匹配二选一,或者的意思,等同于[AB]
(AB)+ 匹配一个或多个括号中的组合
\* 星号本身,转义星号本身
2,
[root@rhel helinbash]# gawk '/^a/' test.txt
a
ab
abab
abbb
ababab aaab [root@rhel helinbash]# gawk '/^a$/' test.txt a [root@rhel helinbash]# gawk '/a$/' test.txt a baaa [root@rhel helinbash]# gawk '/..../' test.txt abab abbb ababab aaab baaa [root@rhel helinbash]# gawk '/^....&/' test.txt [root@rhel helinbash]# gawk '/^....$/' test.txt abab abbb aaab baaa [root@rhel helinbash]# cat test.txt a ab abab abbb ababab aaab baaa [root@rhel helinbash]# 3, [root@rhel helinbash]# vim test.txt [root@rhel helinbash]# cat test.txt a ab abab abbb ababab aaab baaa c.tx [root@rhel helinbash]# gawk '/^....$/' test.txt abab abbb aaab baaa c.tx [root@rhel helinbash]# gawk '/^.\...$/' test.txt c.tx [root@rhel helinbash]# 4, [root@rhel helinbash]# gawk '/^a*$/' test.txt a [root@rhel helinbash]# cat test.txt a ab abab abbb ababab aaab baaa c.tx 5, [root@rhel helinbash]# vim test.txt [root@rhel helinbash]# gawk '/^a*$/' test.txt a aaaaa aaaa [root@rhel helinbash]# cat test.txt a ab abab abbb ababab aaab baaa c.tx aaaaa aaaa [root@rhel helinbash]# 6, [root@rhel helinbash]# gawk '/^a*$/' test.txt a aaaaa aaaa [root@rhel helinbash]# vim test.txt [root@rhel helinbash]# cat test.txt a ab abab abbb ababab aaab baaa c.tx aaaaa aaaa [root@rhel helinbash]# gawk '/^a*$/' test.txt # 注: * 可以匹配空行就是出现了0次 a aaaaa aaaa [root@rhel helinbash]# gawk '/^a+$/' test.txt # 注: 这个不可以匹配空行至少出现1次 a aaaaa aaaa [root@rhel helinbash]# [root@rhel helinbash]# gawk '/^a?$/' test.txt a [root@rhel helinbash]# [root@rhel helinbash]# gawk '/^[ab]*/' ./test.txt a ab abab abbb ababab aaab baaa c.tx #为什么会出现,因为ab出现了0次,也就是*的含义 aaaaa aaaa [root@rhel helinbash]# gawk '/^[ab]*$/' ./test.txt a ab abab abbb ababab aaab baaa aaaaa aaaa [root@rhel helinbash]# [root@rhel helinbash]# gawk '/^[^ab]*$/' ./test.txt c.tx [root@rhel helinbash]# [root@rhel helinbash]# cat test.txt a ab abab abbb ababab aaab baaa c.tx aaaaa aaaa [root@rhel helinbash]# 7, [root@rhel helinbash]# cat test.txt a ab abab abbb ababab aaab baaa c.tx aaaaa aaaa dddddddddddddd ffffffffff faaaaaaaaaa kjjjjjjj [root@rhel helinbash]# gawk '/^[^ab]*$/' ./test.txt c.tx dddddddddddddd ffffffffff kjjjjjjj [root@rhel helinbash]# 8, [root@rhel helinbash]# gawk '/(ab)*/' test.txt a ab abab abbb ababab aaab baaa c.tx aaaaa aaaa dddddddddddddd ffffffffff faaaaaaaaaa kjjjjjjj [root@rhel helinbash]# [root@rhel helinbash]# gawk '/^(ab)*$/' test.txt ab abab ababab [root@rhel helinbash]# 9, [root@rhel helinbash]# gawk '/^(ab)\{3\}*$/' test.txt #{3}这种不支持 [root@rhel helinbash]#
linux awk 正则表达式、正则运算符详细介绍
一、awk Extended Regular Expression (ERES)基础表达式符号介绍
字符 | 功能 |
---|---|
+ | 指定如果一个或多个字符或扩展正则表达式的具体值(在 +(加号)前)在这个字符串中,则字符串匹配。命令行: awk '/smith+ern/' testfile 将包含字符 smit,后跟一个或多个 h 字符,并以字符 ern 结束的字符串的任何记录打印至标准输出。此示例中的输出是: smithern, harry smithhern, anne |
? | 指定如果零个或一个字符或扩展正则表达式的具体值(在 ?(问号)之前)在字符串中,则字符串匹配。命令行: awk '/smith?/' testfile 将包含字符 smit,后跟零个或一个 h 字符的实例的所有记录打印至标准输出。此示例中的输出是: smith, alan smithern, harry smithhern, anne smitters, alexis |
| | 指定如果以 |(垂直线)隔开的字符串的任何一个在字符串中,则字符串匹配。命令行: awk '/allen | alan /' testfile 将包含字符串 allen 或 alan 的所有记录打印至标准输出。此示例中的输出是: smiley, allen smith, alan |
( ) | 在正则表达式中将字符串组合在一起。命令行: awk '/a(ll)?(nn)?e/' testfile 将具有字符串 ae 或 alle 或 anne 或 allnne 的所有记录打印至标准输出。此示例中的输出是: smiley, allen smithhern, anne |
{m} | 指定如果正好有 m 个模式的具体值位于字符串中,则字符串匹配。命令行: awk '/l{2}/' testfile 打印至标准输出 smiley, allen |
{m,} | 指定如果至少 m 个模式的具体值在字符串中,则字符串匹配。命令行: awk '/t{2,}/' testfile 打印至标准输出: smitters, alexis |
{m, n} | 指定如果 m 和 n 之间(包含的 m 和 n)个模式的具体值在字符串中(其中m <= n),则字符串匹配。命令行: awk '/er{1, 2}/' testfile 打印至标准输出: smithern, harry smithern, anne smitters, alexis |
[String] | 指定正则表达式与方括号内 String 变量指定的任何字符匹配。命令行: awk '/sm[a-h]/' testfile 将具有 sm 后跟以字母顺序从 a 到 h 排列的任何字符的所有记录打印至标准输出。此示例的输出是: smawley, andy |
[^ String] | 在 [ ](方括号)和在指定字符串开头的 ^ (插入记号) 指明正则表达式与方括号内的任何字符不匹配。这样,命令行: awk '/sm[^a-h]/' testfile 打印至标准输出: smiley, allen smith, alan smithern, harry smithhern, anne smitters, alexis |
~,!~ | 表示指定变量与正则表达式匹配(代字号)或不匹配(代字号、感叹号)的条件语句。命令行: awk '$1 ~ /n/' testfile 将第一个字段包含字符 n 的所有记录打印至标准输出。此示例中的输出是: smithern, harry smithhern, anne |
^ | 指定字段或记录的开头。命令行: awk '$2 ~ /^h/' testfile 将把字符 h 作为第二个字段的第一个字符的所有记录打印至标准输出。此示例中的输出是: smithern, harry |
$ | 指定字段或记录的末尾。命令行: awk '$2 ~ /y$/' testfile 将把字符 y 作为第二个字段的最后一个字符的所有记录打印至标准输出。此示例中的输出是: smawley, andy smithern, harry |
. (句号) | 表示除了在空白末尾的终端换行字符以外的任何一个字符。命令行: awk '/a..e/' testfile 将具有以两个字符隔开的字符 a 和 e 的所有记录打印至标准输出。此示例中的输出是: smawley, andy smiley, allen smithhern, anne |
*(星号) | 表示零个或更多的任意字符。命令行: awk '/a.*e/' testfile 将具有以零个或更多字符隔开的字符 a 和 e 的所有记录打印至标准输出。此示例中的输出是: smawley, andy smiley, allen smithhern, anne smitters, alexis |
\ (反斜杠) | 转义字符。当位于在扩展正则表达式中具有特殊含义的任何字符之前时,转义字符除去该字符的任何特殊含义。例如,命令行: /a\/\// 将与模式 a // 匹配,因为反斜杠否定斜杠作为正则表达式定界符的通常含义。要将反斜杠本身指定为字符,则使用双反斜杠。有关反斜杠及其使用的更多信息,请参阅以下关于转义序列的内容。 |
与PERs相比,主要是一些结合类型表示符没有了:包括:”\d,\D,\s,\S,\t,\v,\n,\f,\r”其它功能基本一样的。 我们常见的软件:javascript,.net,java支持的正则表达式,基本上是:EPRs类型。
二、awk 常见调用正则表达式方法
awk语句中:
awk ‘/REG/{action}’
/REG/为正则表达式,可以将$0中,满足条件记录 送入到:action进行处理.
awk正则运算语句(~,~!等同!~)
[chengmo@centos5 ~]$ awk 'BEGIN{info="this is a test";if( info ~ /test/){print "ok"}}'
ok
awk内置使用正则表达式函数
gsub( Ere, Repl, [ In ] )
sub( Ere, Repl, [ In ] )
match( String, Ere )
split( String, A, [Ere] )
详细函数使用,可以参照:linux awk 内置函数详细介绍(实例)
通过上面细述,不知道大家有没有对awk正则表达式有一个更加清楚的认识。 有什么问题可以与我交流!
对于awk而言,正则表达式是置于两个正斜杠之间(‘’)、由字符组成的模式。Awk支持 使用正则表达式元字符对正则表达式进行某种方式修改。如果输入行中的某个字符串与正则表达式相匹配,则最终条件为真,于是执行与该表达式关联的所有操作。 如果没有指定操作,则打印与正则表达式匹配的记录
元字符 | 说明 |
^ | 在串首匹配 |
$ | 在串尾匹配 |
. | 匹配单个任意字符 |
* | 匹配零个或多个前导字符 |
+ | 匹配一个或多个前导字符 |
? | 匹配零个或一个前导字符 |
|(A|B) | 指定如果以 |(垂直线)隔开的字符串的任何一个在字符串中,则字符串匹配,匹配A或B |
[ABC] | 匹配指定字符组(即A、B和C)中任一字符 |
[^ABC] | 匹配任何一个不在指定字符组(即A、B和C)中的字符 |
[A-Z] | 匹配A至Z之间的任一字符 |
(AB)+ | 将字符串组合在一起,匹配一个或多个AB的组合,例如:AB、ABAB |
~,!~ | 表示指定变量与正则表达式匹配(代字号)或不匹配(代字号、感叹号)的条件语句 |
{m, n} | 指定如果 m 和 n 之间(包含的 m 和 n)个模式的具体值在字符串中(其中m<= n),则字符串匹配 |
\ | 转义字符。位于正则表达式中具有特殊含义的任何字符之前时,转义字符除去其任何特殊含义 |
& | 用于替代串中,代表查找串中匹配到的内容 |
表-Awk的正则表达式元字符
元字符 | 说明 |
\<>/ | 单词定位 |
\(\) | 向前引用 |
\{\} | 重复 |
本教程首先对正则表达式进行了基本的解释,然后介绍了 grep
和 sed
。grep
是一个强大的搜索实用程序,而 sed
则是一个更加强大的搜索和替换实用程序。awk
则更进一步,它在全功能的命令行编程语言中使用正则表达式。正如 sed
一样,当在命令行上使用 awk
时,它接受基于行的输入。awk
一次解释一行输入,但是与 sed
不同,它将该行上的每个部分作为变量来处理,这些变量可用作内联代码的输入和输出。
应该指出的是,AWK(大写)是一个可用于编写脚本(而不只是在命令行上使用)的全功能编程语言,但本教程集中于 awk
,后者是动态解释 AWK 命令的命令行实用程序。
顺便提一下,任何人阅读到这里都会考虑如何实际运用所学到的知识,我刚才就使用 grep
在某些旧代码中搜索理想的 awk
示例:
grep awk */*.pl |
大多数系统管理员或程序员每天都会看到这些工具的应用。下面是我的输出中的一些行:
Edaemon/m_checkcurrentdisk.pl:$freespace = `awk '(NR==1) {print \$4 / 1024 / 1024}' grep.tmp`; Edaemon/m_getdatetime.pl:$month = `awk '(NR==1) {print \$2}' datetime.txt`; Odaemon/odaemon.beowulf.dvd.pl:$filesize = `awk '(NR==1) {print \$1}' temp.txt`; |
这些是非常好的示例,因为它们说明了非常基础的 awk
应用。对于您的第一次尝试,甚至可以使它更简单。对于您的 awk
测试,请在一个空目录中创建以下文件(每个文件的内容无关紧要,并且它们可以是空的)。
Screenshot_1.jpg Screenshot_2.jpg Screenshot_3.jpg awk.txt regular.txt sed.txt |
缺省情况下,awk
读取输入文件中的每一行,并将内容分离为由空格确定的变量。在非常简单的示例中,您可以使用 ls
的输出作为 awk
的输入并打印结果。此示例结合使用管道字符 (|) 和 ls
来将输出发送到 awk
:
ls | awk ' { print $1 } ' |
awk
随后打印每行上的第一项,在此例中为每行上的唯一项:
Screenshot_1.jpg Screenshot_2.jpg Screenshot_3.jpg awk.txt regular.txt sed.txt |
这确实是非常基本的功能。对于下一个示例,请使用 ls -l
来为 awk
生成多列输入:
ls -l |
不同系统的 ls
实现稍有差别,下面是一些示例输出:
total 432 -rw-rw-rw- 1 guest guest 169074 Oct 15 14:51 Screenshot_1.jpg -rw-rw-rw- 1 guest guest 23956 Oct 15 20:56 Screenshot_2.jpg -rw-rw-rw- 1 guest guest 12066 Oct 15 20:57 Screenshot_3.jpg -rw-r--r-- 1 tuser tuser 227 Oct 15 20:16 awk.txt -rw-r--r-- 1 tuser tuser 233 Oct 15 19:35 regular.txt -rw-r--r-- 1 tuser tuser 227 Oct 15 23:16 sed.txt |
请注意,文件所有者是每行上的第三个项,文件名是每行上的第九个项(缺省情况下,awk
中的项之间用空格分隔)。通过打印每行上的第三和第九个变量,您可以使用 awk
来从该列表提取文件所有者和文件名。下面是完成这项工作的命令:
ls -l | awk ' { print $3 " " $9 } ' |
您将注意到,awk
中的 print
命令有两个引号,而且引号中有一个空格。这只是为了在输出的文件所有者和文件名之间打印一个空格:
guest Screenshot_1.jpg guest Screenshot_2.jpg guest Screenshot_3.jpg tuser awk.txt tuser regular.txt tuser sed.txt |
您可以在 awk
打印语句中的变量之间的引号中放置任何文本。
现在您已经学习了如何使用 awk
的基础知识,但本教程不是关于正则表达式的吗?awk
中大量使用了正则表达式。最常见的示例是在 awk
命令前附加一个正则表达式,用于指定您想要操作的行。与 sed
一样,awk
中的正则表达式位于两个正斜杠之间。例如,如果您只希望操作 tuser
所拥有的文件,则可以使用以下命令:
ls -l | awk ' /tuser/ { print $3 " " $9 } ' |
该命令产生以下输出:
tuser awk.txt tuser regular.txt tuser sed.txt |
在另一个示例中,您可能希望更改每个文本文件的文件扩展名而不更改图像文件。为此,您将需要使用句点而不是空格来分隔输入变量,然后使用正则表达式来指示您仅希望搜索文本文件。若要基于句点来分隔变量,可以使用 -F
标志,后跟后跟您希望使用的字符(用引号引起来)。尝试此示例,通过管道将 awk
输出发送到某个 Shell(此 Shell 将执行 awk
生成的命令):
s | awk -F"." ' /txt/ { print "mv " $1 "." $2 " " $1 ".doc" } ' | bash |
后续的 ls -l
将显示新的文件名:
-rw-rw-rw- 1 guest guest 169074 Oct 15 14:51 Screenshot_1.jpg -rw-rw-rw- 1 guest guest 23956 Oct 15 20:56 Screenshot_2.jpg -rw-rw-rw- 1 guest guest 12066 Oct 15 20:57 Screenshot_3.jpg -rw-r--r-- 1 tuser tuser 227 Oct 15 20:16 awk.doc -rw-r--r-- 1 tuser tuser 233 Oct 15 19:35 regular.doc -rw-r--r-- 1 tuser tuser 227 Oct 15 23:16 sed.doc |
记住,这些只是 awk
的入门基础知识,但是 AWK 是一种全功能的编程语言,所具有的功能远远超出了本教程所介绍的内容。请查看一下 awk man
页。如果您希望学习更多的知识,花钱买一本优秀的图书是明智的。
AWK是一种优良的文本处理工具。它不仅是linux中也是任何环境中现有的功能最强大的数据处理引擎之一。这种编程及数据库访问语言(其名称得自 于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母)的最大功能取决于一个人所拥有的知识
一、AWK的用法:
1、在命令行模式的直接使用。 格式为: awk ‘pattern {action}’
2、将awk命令写入脚本,并以#!/bin/awk -f命令解释器作为脚本的首行,设置脚本的可执行权限,通过键入脚本名称来调用它。格式为./testscript.awk filename。等同于shell脚本的方法。
3、将awk命令插入一个单独文件然后执行。格式为 awk -f awkscript filename
第 一种格式常见的是awk 'BEGIN {print "this is the start"}{print $1,$2,$3}END{print "this is the end"}' filename。其中BEGIN和END中间是模式,END后是动作。BEGIN和END可以省去,模式一般是匹配搜索使用
二、AWK排查错误常见的问题
1、确保整个AWK用单引号括起来;2、确保单引号内所有的括号或引号成对出现;3、确保用大括号括起动作语句,用小括号括起条件语句;4有时候要检查是否有文件名或者BEGIN等
三、AWK内置字符串变量函数
gsub(r,s)
|
在整个$0中
用s代替r
|
gsub(r,s,t)
|
在
整个t中用s替代r
|
index(s,t)
|
返回s中字符串t的第一位置
|
length(s)
|
返回s长度
|
match(s,r)
|
测试s是否包含匹配r的字符串
|
split(s,a,fs)
|
在fs上将s分成序列a,放在数组a里。返回段数的数值,
|
sprint(fmt,exp)
|
返回经fmt格式化后的exp
|
sub(r,s)
|
用$0中最左边最长的子串代替s
|
substr(s,p)
|
返回字符串s中从p开始的后缀部分
|
substr(s,p,n)
|
返回字符串s中从p开始长度为n的后缀部分
|
四、AWK的内置环境变量
$n | 当前记录的第n个字段,字段间由FS分隔。 |
$0 | 完整的输入记录。在文本中一般指行信息内容 |
ARGC | 命令行参数的数目。 |
ARGIND | 命令行中当前文件的位置(从0开始算)。 |
ARGV | 包含命令行参数的数组。 |
CONVFMT | 数字转换格式(默认值为%.6g) |
ENVIRON | 环境变量关联数组。 |
ERRNO | 最后一个系统错误的描述。 |
FIELDWIDTHS | 字段宽度列表(用空格键分隔)。 |
FILENAME | 当前文件名。 |
FNR | 同NR,但相对于当前文件。 |
FS | 字段分隔符(默认是任何空格)。可以用户指定 |
IGNORECASE | 如果为真,则进行忽略大小写的匹配。 |
NF | 当前记录中的字段数。$NF指最后一个段内容 |
NR | 当前记录数。在文本中一般指多少行 |
OFMT | 数字的输出格式(默认值是%.6g)。 |
OFS | 输出字段分隔符(默认值是一个空格)。 |
ORS | 输出记录分隔符(默认值是一个换行符)。 |
RLENGTH | 由match函数所匹配的字符串的长度。 |
RS | 记录分隔符(默认是一个换行符)。 |
RSTART | 由match函数所匹配的字符串的第一个位置。 |
SUBSEP | 数组下标分隔符(默认值是\034)。 |
五、AWK内置操作符
= += -= *= /= %= ^= **= | 赋值 如a+=10代表a+10 |
?: | C条件表达式,a>b?a:b表示a大于b如为真返回a,如为假返回b |
|| | 逻辑或。只要一个为真即为真。 |
&& | 逻辑与。只要一个为假即为假。需两个同时为真才为真。 |
~ ~! | 匹配正则表达式和不匹配正则表达式。经常针对文本搜索 |
< <= > >= != == | 关系运算符 |
空格 | 连接 |
+ - | 加,减 |
* / & | 乘,除与求余 |
+ - ! | 一元加,减和逻辑非 |
^ *** | 求幂 |
++ -- | 增加或减少,作为前缀或后缀。这个一定要区分清楚++a与a++ |
$ | 字段引用 |
in | 数组成员 |
六、AWK元字符:\(转义字符)、^ $ [] | * + ?。其中+和?只能在AWK中使用不能再sed和grep中使用。+表示匹配一个或多个字符;?表示匹配0或1个字符。
相关阅读:
sed与awk常用功能 http://www.linuxidc.com/Linux/2013-06/86099.htm
Linux下shell编程常用grep\awk\sed语法 http://www.linuxidc.com/Linux/2013-07/87047.htm
Linux下Shell编程——awk编程 http://www.linuxidc.com/Linux/2013-06/85527.htm
文本处理工具awk详解 http://www.linuxidc.com/Linux/2013-05/84248.htm
Linux awk命令使用详解 http://www.linuxidc.com/Linux/2012-12/77082.htm
awk正则表达式和内置函数的使用方法实例详解
awk正则表达式及内置函数实例详解:
1、模糊匹配:
awk ‘{if($3~/97/) print $0}' data.f:如果第三项中含有”97”则打印该行
awk ‘{if($4!~/ufcx/) print $0}' data.f:如果第三项中不含ufcx有则打印
2、精确匹配:
awk ‘{if($5==66) print $0}' data.f:如果第五项是66则打印
awk ‘{if($5!=66)print $0}' data.f : 如果第五项不是66则打印
awk ‘{if($1>$5) print $0}' data.f:如果第一项大于第五项则打印
3、大小写匹配:
awk ‘{if(/[Ss]ept/) print $0}' data.f:符合,则打印一行。
awk ‘/[Ss]ept/ {print $2}' data.f:符合,则打印第二字段
4、任意匹配:
awk ‘{if($2 ~/^.e/) print $0}' data.f:第二字段中,第二个字符为e,输出
awk ‘{if($4 ~/(lps|fcx)/) print $0}' data.f:第四个字段含有lps或fcx则输出
5、&&,||:
awk ‘{if($3 ~/1993/ && $2==”sept”) print $0}' data.f:两边都真则输出
awk ‘{if($3 ~/a9/ || $2==”sept”) print $0}' data.f:一边为真则输出
6、变量定义:
awk ‘{date=$2;price=$5; if(date ~/[Ss]ept/) print “price is ” price}' data.f:变量定义,满足date是sept或者Sept的将price输出。
7、修改数值(源文件数值不变)
awk ‘{BASELINE=42; if($1>BASELINE) $5=$5+100; print $0}' data.f:三行程序,以“;”分割
如果修改的是文本域,就要添加“”””。例如:awk ‘{if($2==”may”) $2=”tt”; print $0}' data.f
上边都是显示所有数据,awk ‘{if($2==”may”) {$2=”tt”; print $0}}' data.f这个只显示修改数据,仔细看看,其实语法和c一样,只是最外边添加了一个{}符号。
8、创建新域:(源文件数值不变)
awk ‘{if($5>$1){$8=$5-$1;print $1,$8}}' data.f:
或者awk ‘{if($5>$1){diff=$5-$1;print $1,diff}}' data.f
9、数据统计:
awk ‘{(total+=$5)}END{print total}' data.f:“{(total+=$5)}”和“{print total}”代表两个不同的代码段,如果没有END每次的累积结果都会输出,END可以理解为代码段落的标志,这样只输出最终结果即{print total}只执行一次。
10、统计文件大小:
ls –l | awk ‘{if(/^[^d]/) total=+$5}END{print “total KB:” total}':/^[^d]/行首匹配可以不写域值$1
11、Awk内置变量:
ARGC 命令行参数个数
ARGV 命令行参数排列
ENVIRON 支持队列中系统环境变量的使用
FILENAME awk浏览的文件名
FNR 浏览文件的记录数
FS 设置输入域分隔符,等价于命令行- F选项
NF 浏览记录的域个数
NR 已读的记录数
OFS 输出域分隔符
ORS 输出记录分隔符
RS 控制记录分隔符
12、awk内置字符串处理函数
gsub ( r, s )在整个$0中用s替代r
gsub ( r, s , t )在整个t中用s替代r
index ( s , t )返回s中字符串t的第一位置
length ( s )返回s长度
match ( s , r )测试s是否包含匹配r的字符串,返回位置
split ( s , a , fs )在fs上将s分成序列a
sprint ( f m t , exp )返回经f m t格式化后的exp
sub ( r, s ,$0) $0中s替换第一次r出现的位置
substr ( s , p )返回字符串s中从p开始的后缀部分
substr ( s , p , n )返回字符串s中从p开始长度为n的后缀部分
13、awk ‘gsub(/6\./,78) {print $0}' data.f:将所有“6.”换成78,并输出
awk ‘{if($2==”Sept”) {sub(/3/,”9″,$0); print $0}}' data.f:只替换第一个出现的
awk ‘BEGIN{print index(“hello”,”lo”)}':输出的值为4
awk ‘{if($3==”3BC1997″) print length($3) ” ” $3}' data.f
awk ‘BEGIN{print match(“ABCD”,”B”)}':输出2
awk ‘BEGIN{print match(“ABCD”,/B/)}':“//”和“”””效果一样
awk ‘BEGIN {print split(“123#234#654″, myarray, “#”)}':返回数组元素个数,123#234#654是字符串,以“#”为分隔符,将字符串放入数组。
awk ‘{if($1==34) print substr($3,2,7)}' data.f
awk ‘BEGIN{print substr(“helloleeboy”,2,7)}':输出ellole
awk ‘BEGIN{print substr(“helloleeboy”,2,7)}' data.f:输出n遍ellole,n为data.f的行数
14、awk ‘BEGIN{print”May\tDay\n\nMay \104\141\171″}':\104\141\171表示Day。\t:tab键,\n:换行,\ddd:八进制
15、echo “65” | awk ‘{printf “%c\n”,$0}':printf函数,和c差不多,输出为A。(ASCII码)
echo “65” | awk ‘{printf “%d\n”,$0}':输出65数字。
awk ‘{printf “%-15s %s\n”,$2,$3}' data.f:“%-15s”左对齐15个字符长度
awk ‘{if(age<$1) print $0}' age=80 data.f和 awk ‘{age=49;if(age<$1) print $0}' data.f结果一样,前者将值传入awk,后者在awk中定义了一个变量。
1. awk简介
awk 是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入、一个或多个文件,或其它命令的输出。它支持用户自定义函数和 动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk的处理文本和数据的方式是这 样的,它逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。如果没有指定处理动作,则把匹配的行显示到标准输出 (屏幕),如果没有指定模式,则所有被操作所指定的行都被处理。awk分别代表其作者姓氏的第一个字母。因为它的作者是三个人,分别是Alfred Aho、Brian Kernighan、Peter Weinberger。gawk是awk的GNU版本,它提供了Bell实验室和GNU的一些扩展。下面介绍的awk是以GUN的gawk为例的,在 linux系统中已把awk链接到gawk,所以下面全部以awk进行介绍。
-
awk [options] 'script' var=value file(s)
-
awk [options] -f scriptfile var=value file(s)
-
-F fs or --field-separator fs
-
指定输入文件折分隔符,fs是一个字符串或者是一个正则表达式,如-F:。
-v var=value or --asign var=value
-
赋值一个用户定义变量。
-f scripfile or --file scriptfile
-
从脚本文件中读取awk命令。
-mf nnn and -mr nnn
-
对nnn值设置内在限制,-mf选项限制分配给nnn的最大块数目;-mr选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适用。
-W compact or --compat, -W traditional or --traditional
-
在兼容模式下运行awk。所以gawk的行为和标准的awk完全一样,所有的awk扩展都被忽略。
-W copyleft or --copyleft, -W copyright or --copyright
-
打印简短的版权信息。
-W help or --help, -W usage or --usage
-
打印全部awk选项和每个选项的简短说明。
-W lint or --lint
-
打印不能向传统unix平台移植的结构的警告。
-W lint-old or --lint-old
-
打印关于不能向传统unix平台移植的结构的警告。
-W posix
-
打开兼容模式。但有以下限制,不识别:/x、函数关键字、func、换码序列以及当fs是一个空格时,将新行作为一个域分隔符;操作符**和**=不能代替^和^=;fflush无效。
-W re-interval or --re-inerval
-
允许间隔正则表达式的使用,参考(grep中的Posix字符类),如括号表达式[[:alpha:]]。
-W source program-text or --source program-text
-
使用program-text作为源代码,可与-f命令混用。
-W version or --version
-
打印bug报告信息的版本。
-
awk脚本是由模式和操作组成的:
-
pattern {action} 如$ awk '/root/' test,或$ awk '$3 < 100' test。
两者是可选的,如果没有模式,则action应用到全部记录,如果没有action,则输出匹配全部记录。默认情况下,每一个输入行都是一条记录,但用户可通过RS变量指定不同的分隔符进行分隔。
模式可以是以下任意一个:
-
/正则表达式/:使用通配符的扩展集。
-
关系表达式:可以用下面运算符表中的关系运算符进行操作,可以是字符串或数字的比较,如$2>%1选择第二个字段比第一个字段长的行。
-
模式匹配表达式:用运算符~(匹配)和~!(不匹配)。
-
模式,模式:指定一个行的范围。该语法不能包括BEGIN和END模式。
-
BEGIN:让用户指定在第一条输入记录被处理之前所发生的动作,通常可在这里设置全局变量。
-
END:让用户在最后一条输入记录被读取之后发生的动作。
Table 1. awk的环境变量
变量 | 描述 |
---|---|
$n | 当前记录的第n个字段,字段间由FS分隔。 |
$0 | 完整的输入记录。 |
ARGC | 命令行参数的数目。 |
ARGIND | 命令行中当前文件的位置(从0开始算)。 |
ARGV | 包含命令行参数的数组。 |
CONVFMT | 数字转换格式(默认值为%.6g) |
ENVIRON | 环境变量关联数组。 |
ERRNO | 最后一个系统错误的描述。 |
FIELDWIDTHS | 字段宽度列表(用空格键分隔)。 |
FILENAME | 当前文件名。 |
FNR | 同NR,但相对于当前文件。 |
FS | 字段分隔符(默认是任何空格)。 |
IGNORECASE | 如果为真,则进行忽略大小写的匹配。 |
NF | 当前记录中的字段数。 |
NR | 当前记录数。 |
OFMT | 数字的输出格式(默认值是%.6g)。 |
OFS | 输出字段分隔符(默认值是一个空格)。 |
ORS | 输出记录分隔符(默认值是一个换行符)。 |
RLENGTH | 由match函数所匹配的字符串的长度。 |
RS | 记录分隔符(默认是一个换行符)。 |
RSTART | 由match函数所匹配的字符串的第一个位置。 |
SUBSEP | 数组下标分隔符(默认值是/034)。 |
awk把每一个以换行符结束的行称为一个记录。
记录分隔符:默认的输入和输出的分隔符都是回车,保存在内建变量ORS和RS中。
$0变量:它指的是整条记录。如$ awk '{print $0}' test将输出test文件中的所有记录。
变量NR:一个计数器,每处理完一条记录,NR的值就增加1。如$ awk '{print NR,$0}' test将输出test文件中所有记录,并在记录前显示记录号。
记录中每个单词称做“域”,默认情况下以空格或tab分隔。awk可跟踪域的个数,并在内建变量NF中保存该值。如$ awk '{print $1,$3}' test将打印test文件中第一和第三个以空格分开的列(域)。
一般通用的元字符集就不讲了,可参考我的Sed和Grep学习笔记。以下几个是gawk专用的,不适合unix版本的awk。
-
/Y
-
匹配一个单词开头或者末尾的空字符串。
/B
-
匹配单词内的空字符串。
/<
-
匹配一个单词的开头的空字符串,锚定开始。
/>
-
匹配一个单词的末尾的空字符串,锚定末尾。
/w
-
匹配一个字母数字组成的单词。
/W
-
匹配一个非字母数字组成的单词。
/‘
-
匹配字符串开头的一个空字符串。
/'
-
匹配字符串末尾的一个空字符串。
可参考我的Grep学习笔记
conditional expression1 ? expression2: expression3,例如:$ awk '{max = {$1 > $3} ? $1: $3: print max}' test。如果第一个域大于第三个域,$1就赋值给max,否则$3就赋值给max。
$ awk '$1 + $2 < 100' test。如果第一和第二个域相加大于100,则打印这些行。
$ awk '$1 > 5 && $2 < 10' test,如果第一个域大于5,并且第二个域小于10,则打印这些行。
范围模板匹配从第一个模板的第一次出现到第二个模板的第一次出现之间所有行。如果有一个模板没出现,则匹配到开头或末尾。如$ awk '/root/,/mysql/' test将显示root第一次出现到mysql第一次出现之间的所有行。
![1](http://man.lupaworld.com/content/manage/ringkee/images/callouts/1.png)
$ cat /etc/passwd | awk -F: '/
![2](http://man.lupaworld.com/content/manage/ringkee/images/callouts/2.png)
NF != 7{/
![3](http://man.lupaworld.com/content/manage/ringkee/images/callouts/3.png)
printf("line %d,does not have 7 fields:%s/n",NR,$0)}/
![4](http://man.lupaworld.com/content/manage/ringkee/images/callouts/4.png)
$1 !~ /[A-Za-z0-9]/{printf("line %d,non alpha and numeric user id:%d: %s/n,NR,$0)}/
![5](http://man.lupaworld.com/content/manage/ringkee/images/callouts/5.png)
$2 == "*" {printf("line %d, no password: %s/n",NR,$0)}'
-
$ awk '/^(no|so)/' test-----打印所有以模式no或so开头的行。
-
$ awk '/^[ns]/{print $1}' test-----如果记录以n或s开头,就打印这个记录。
-
$ awk '$1 ~/[0-9][0-9]$/(print $1}' test-----如果第一个域以两个数字结束就打印这个记录。
-
$ awk '$1 == 100 || $2 < 50' test-----如果第一个或等于100或者第二个域小于50,则打印该行。
-
$ awk '$1 != 10' test-----如果第一个域不等于10就打印该行。
-
$ awk '/test/{print $1 + 10}' test-----如果记录包含正则表达式test,则第一个域加10并打印出来。
-
$ awk '{print ($1 > 5 ? "ok "$1: "error"$1)}' test-----如果第一个域大于5则打印问号后面的表达式值,否则打印冒号后面的表达式值。
-
$ awk '/^root/,/^mysql/' test----打印以正则表达式root开头的记录到以正则表达式mysql开头的记录范围内的所有记录。如果找到一个新的正则表达式root开头的记录,则继续打印直到下一个以正则表达式mysql开头的记录为止,或到文件末尾。
-
在awk中,变量不需要定义就可以直接使用,变量类型可以是数字或字符串。
-
赋值格式:Variable = expression,如$ awk '$1 ~/test/{count = $2 + $3; print count}' test,上式的作用是,awk先扫描第一个域,一旦test匹配,就把第二个域的值加上第三个域的值,并把结果赋值给变量count,最后打印出来。
-
awk 可以在命令行中给变量赋值,然后将这个变量传输给awk脚本。如$ awk -F: -f awkscript month=4 year=2004 test,上式的month和year都是自定义变量,分别被赋值为4和2004。在awk脚本中,这些变量使用起来就象是在脚本中建立的一样。注意,如果参数前面出现test,那么在BEGIN语句中的变量就不能被使用。
-
域变量也可被赋值和修改,如$ awk '{$2 = 100 + $1; print }' test,上式表示,如果第二个域不存在,awk将计算表达式100加$1的值,并将其赋值给$2,如果第二个域存在,则用表达式的值覆盖$2原来的值。再例如:$ awk '$1 == "root"{$1 ="test";print}' test,如果第一个域的值是“root”,则把它赋值为“test”,注意,字符串一定要用双引号。
-
内建变量的使用。变量列表在前面已列出,现在举个例子说明一下。$ awk -F: '{IGNORECASE=1; $1 == "MARY"{print NR,$1,$2,$NF}'test,把IGNORECASE设为1代表忽略大小写,打印第一个域是mary的记录数、第一个域、第二个域和最后一个域。
BEGIN 模块后紧跟着动作块,这个动作块在awk处理任何输入文件之前执行。所以它可以在没有任何输入的情况下进行测试。它通常用来改变内建变量的值,如OFS, RS和FS等,以及打印标题。如:$ awk 'BEGIN{FS=":"; OFS="/t"; ORS="/n/n"}{print $1,$2,$3} test。上式表示,在处理输入文件以前,域分隔符(FS)被设为冒号,输出文件分隔符(OFS)被设置为制表符,输出记录分隔符(ORS)被设置为两个换行符。$ awk 'BEGIN{print "TITLE TEST"}只打印标题。
END不匹配任何的输入文件,但是执行动作块中的所有动作,它在整个输入文件处理完成后被执行。如$ awk 'END{print "The number of records is" NR}' test,上式将打印所有被处理的记录数。
-
awk 可使用shell的重定向符进行重定向输出,如:$ awk '$1 = 100 {print $1 > "output_file" }' test。上式表示如果第一个域的值等于100,则把它输出到output_file中。也可以用>>来重定向输出,但不清空文件,只做追加操作。
-
输出重定向需用到getline函数。getline从标准输入、管道或者当前正在处理的文件之外的其他输入文件获得输入。它负责从输入获得下一行的内容,并给NF,NR和FNR等内建变量赋值。如果得到一条记录,getline函数返回1,如果到达文件的末尾就返回0,如果出现错误,例如打开文件失败,就返回-1。如:
$ awk 'BEGIN{ "date" | getline d; print d}' test。执行linux的date命令,并通过管道输出给getline,然后再把输出赋值给自定义变量d,并打印它。
$ awk 'BEGIN{"date" | getline d; split(d,mon); print mon[2]}' test。执行shell的date命令,并通过管道输出给getline,然后getline从管道中读取并将输入赋值给d,split函数把变量d转化成数组mon,然后打印数组mon的第二个元素。
$ awk 'BEGIN{while( "ls" | getline) print}',命令ls的输出传递给geline作为输入,循环使getline从ls的输出中读取一行,并把它打印到屏幕。这里没有输入文件,因为 BEGIN块在打开输入文件前执行,所以可以忽略输入文件。
$ awk 'BEGIN{printf "What is your name?"; getline name < "/dev/tty" } $1 ~name {print "Found" name on line ", NR "."} END{print "See you," name "."} test。在屏幕上打印”What is your name?",并等待用户应答。当一行输入完毕后,getline函数从终端接收该行输入,并把它储存在自定义变量name中。如果第一个域匹配变量 name的值,print函数就被执行,END块打印See you和name的值。
$ awk 'BEGIN{while (getline < "/etc/passwd" > 0) lc++; print lc}'。awk将逐行读取文件/etc/passwd的内容,在到达文件末尾前,计数器lc一直增加,当到末尾时,打印lc的值。注意,如果文件不存在,getline返回-1,如果到达文件的末尾就返回0,如果读到一行,就返回1,所以命令 while (getline < "/etc/passwd")在文件不存在的情况下将陷入无限循环,因为返回-1表示逻辑真。
-
可以在awk中打开一个管道,且同一时刻只能有一个管道存在。通过close()可关闭管道。如:$ awk '{print $1, $2 | "sort" }' test END {close("sort")}。awd把print语句的输出通过管道作为linux命令sort的输入,END块执行关闭管道操作。
-
system函数可以在awk中执行linux的命令。如:$ awk 'BEGIN{system("clear")'。
-
fflush函数用以刷新输出缓冲区,如果没有参数,就刷新标准输出的缓冲区,如果以空字符串为参数,如fflush(""),则刷新所有文件和管道的输出缓冲区。
awk中的条件语句是从C语言中借鉴过来的,可控制程序的流程。
格式:
{if (expression){
statement; statement; ...
}
}
$ awk '{if ($1 <$2) print $2 "too high"}' test。如果第一个域小于第二个域则打印。
$ awk '{if ($1 < $2) {count++; print "ok"}}' test.如果第一个域小于第二个域,则count加一,并打印ok。
格式:
{if (expression){
statement; statement; ...
}
else{
statement; statement; ...
}
}
$ awk '{if ($1 > 100) print $1 "bad" ; else print "ok"}' test。如果$1大于100则打印$1 bad,否则打印ok。
$ awk '{if ($1 > 100){ count++; print $1} else {count--; print $2}' test。如果$1大于100,则count加一,并打印$1,否则count减一,并打印$1。
-
awk有三种循环:while循环;for循环;special for循环。
-
$ awk '{ i = 1; while ( i <= NF ) { print NF,$i; i++}}' test。变量的初始值为1,若i小于可等于NF(记录中域的个数),则执行打印语句,且i增加1。直到i的值大于NF.
-
$ awk '{for (i = 1; i<NF; i++) print NF,$i}' test。作用同上。
-
breadkcontinue语句。break用于在满足条件的情况下跳出循环;continue用于在满足条件的情况下忽略后面的语句,直接返回循环的顶端。如:
{for ( x=3; x<=NF; x++)
if ($x<0){print "Bottomed out!"; break}}
{for ( x=3; x<=NF; x++)
if ($x==0){print "Get next item"; continue}} -
next语句从输入文件中读取一行,然后从头开始执行awk脚本。如:
{if ($1 ~/test/){next}
else {print}
} -
exit语句用于结束awk程序,但不会略过END块。退出状态为0代表成功,非零值表示出错。
awk中的数组的下标可以是数字和字母,称为关联数组。
-
用变量作为数组下标。如:$ awk {name[x++]=$2};END{for(i=0;i<NR;i++) print i,name[i]}' test。数组name中的下标是一个自定义变量x,awk初始化x的值为0,在每次使用后增加1。第二个域的值被赋给name数组的各个元素。在END 模块中,for循环被用于循环整个数组,从下标为0的元素开始,打印那些存储在数组中的值。因为下标是关健字,所以它不一定从0开始,可以从任何值开始。
-
special for循环用于读取关联数组中的元素。格式如下:
{for (item in arrayname){
$ awk '/^tom/{name[NR]=$1}; END{for(i in name){print name[i]}}' test。打印有值的数组元素。打印的顺序是随机的。
print arrayname[item]
}
} -
用字符串作为下标。如:count["test"]
-
用域值作为数组的下标。一种新的for循环方式,for (index_value in array) statement。如:$ awk '{count[$1]++} END{for(name in count) print name,count[name]}' test。该语句将打印$1中字符串出现的次数。它首先以第一个域作数组count的下标,第一个域变化,索引就变化。
-
delete 函数用于删除数组元素。如:$ awk '{line[x++]=$1} END{for(x in line) delete(line[x])}' test。分配给数组line的是第一个域的值,所有记录处理完成后,special for循环将删除每一个元素。
-
sub函数匹配记录中最大、最靠左边的子字符串的正则表达式,并用替换字符串替换这些字符串。如果没有指定目标字符串就默认使用整个记录。替换只发生在第一次匹配的时候。格式如下:
sub (regular expression, substitution string):
sub (regular expression, substitution string, target string)实例:
$ awk '{ sub(/test/, "mytest"); print }' testfile
$ awk '{ sub(/test/, "mytest"); $1}; print }' testfile第一个例子在整个记录中匹配,替换只发生在第一次匹配发生的时候。如要在整个文件中进行匹配需要用到gsub
第二个例子在整个记录的第一个域中进行匹配,替换只发生在第一次匹配发生的时候。
-
gsub函数作用如sub,但它在整个文档中进行匹配。格式如下:
gsub (regular expression, substitution string)
gsub (regular expression, substitution string, target string)实例:
$ awk '{ gsub(/test/, "mytest"); print }' testfile
$ awk '{ gsub(/test/, "mytest"), $1 }; print }' testfile第一个例子在整个文档中匹配test,匹配的都被替换成mytest。
第二个例子在整个文档的第一个域中匹配,所有匹配的都被替换成mytest。
-
index函数返回子字符串第一次被匹配的位置,偏移量从位置1开始。格式如下:
index(string, substring)
实例:
$ awk '{ print index("test", "mytest") }' testfile
实例返回test在mytest的位置,结果应该是3。
-
length函数返回记录的字符数。格式如下:
length( string )
length实例:
$ awk '{ print length( "test" ) }'
$ awk '{ print length }' testfile第一个实例返回test字符串的长度。
第二个实例返回testfile文件中第条记录的字符数。
-
substr函数返回从位置1开始的子字符串,如果指定长度超过实际长度,就返回整个字符串。格式如下:
substr( string, starting position )
substr( string, starting position, length of string )实例:
$ awk '{ print substr( "hello world", 7,11 ) }'
上例截取了world子字符串。
-
match函数返回在字符串中正则表达式位置的索引,如果找不到指定的正则表达式则返回0。match函数会设置内建变量RSTART为字符串中子字符串的开始位置,RLENGTH为到子字符串末尾的字符个数。substr可利于这些变量来截取字符串。函数格式如下:
match( string, regular expression )
实例:
$ awk '{start=match("this is a test",/[a-z]+$/); print start}'
$ awk '{start=match("this is a test",/[a-z]+$/); print start, RSTART, RLENGTH }'第一个实例打印以连续小写字符结尾的开始位置,这里是11。
第二个实例还打印RSTART和RLENGTH变量,这里是11(start),11(RSTART),4(RLENGTH)。
-
toupper和tolower函数可用于字符串大小间的转换,该功能只在gawk中有效。格式如下:
toupper( string )
tolower( string )实例:
$ awk '{ print toupper("test"), tolower("TEST") }'
-
split函数可按给定的分隔符把字符串分割为一个数组。如果分隔符没提供,则按当前FS值进行分割。格式如下:
split( string, array, field separator )
split( string, array )实例:
$ awk '{ split( "20:18:00", time, ":" ); print time[2] }'
上例把时间按冒号分割到time数组内,并显示第二个数组元素18。
-
systime函数返回从1970年1月1日开始到当前时间(不计闰年)的整秒数。格式如下:
systime()
实例:
$ awk '{ now = systime(); print now }'
-
strftime函数使用C库中的strftime函数格式化时间。格式如下:
systime( [format specification][,timestamp] )
Table 3. 日期和时间格式说明符
格式 描述 %a 星期几的缩写(Sun) %A 星期几的完整写法(Sunday) %b 月名的缩写(Oct) %B 月名的完整写法(October) %c 本地日期和时间 %d 十进制日期 %D 日期 08/20/99 %e 日期,如果只有一位会补上一个空格 %H 用十进制表示24小时格式的小时 %I 用十进制表示12小时格式的小时 %j 从1月1日起一年中的第几天 %m 十进制表示的月份 %M 十进制表示的分钟 %p 12小时表示法(AM/PM) %S 十进制表示的秒 %U 十进制表示的一年中的第几个星期(星期天作为一个星期的开始) %w 十进制表示的星期几(星期天是0) %W 十进制表示的一年中的第几个星期(星期一作为一个星期的开始) %x 重新设置本地日期(08/20/99) %X 重新设置本地时间(12:00:00) %y 两位数字表示的年(99) %Y 当前月份 %Z 时区(PDT) %% 百分号(%) 实例:
$ awk '{ now=strftime( "%D", systime() ); print now }'
$ awk '{ now=strftime("%m/%d/%y"); print now }'