awk进阶

变量名 描述
FS 输入字段分隔符,默认是空格或制表符
OFS 输出字段分隔符,默认是空格
RS 输入记录分隔符,默认是换行符\n
ORS 输出记录分隔符,默认是换行符\n
NF 统计当前记录中字段个数
NR 统计记录编号,每处理一行记录,编号就会+1
FNR 统计记录编号,每处理一行记录,编号也会+1,与 NR 不同的是,处理第二个文件时,编号会重新计数。
ARGC 命令行参数数量
ARGV 命令行参数数组序列数组,下标从 0 开始,ARGV[0]是 awk
ARGIND 当前正在处理的文件索引值。第一个文件是 1,第二个文件是 2,以此类推
ENVIRON 当前系统的环境变量
FILENAME 输出当前处理的文件名
IGNORECASE 忽略大小写
SUBSEP 数组中下标的分隔符,默认为"\034"

示例:

FS 和 OFS

在程序开始前重新赋值 FS 变量,改变默认分隔符为冒号,与-F 一样。

# awk 'BEGIN{FS=":"}{print $1,$2}' /etc/passwd |head -n5
root x
bin x
daemon x
adm x
lp x

也可以使用-v 来重新赋值这个变量

# awk -vFS=':' '{print $1,$2}' /etc/passwd |head -n5 # 中间逗号被换成了 OFS 的默
认值
root x
bin x
daemon x
adm x
lp x

由于 OFS 默认以空格分隔,反向引用多个字段分隔的也是空格,如果想指定输出分隔符这样

# awk 'BEGIN{FS=":";OFS=":"}{print $1,$2}' /etc/passwd |head -n5
root:x
bin:x
daemon:x
adm:x
lp:x

也可以通过字符串拼接实现分隔

# awk 'BEGIN{FS=":"}{print $1"#"$2}' /etc/passwd |head -n5
root#x
bin#x
daemon#x
adm#x
lp#x
2)RS 和 ORS
RS 默认是\n 分隔每行,如果想指定以某个字符作为分隔符来处理记录:
# echo "www.baidu.com/user/test.html" |awk 'BEGIN{RS="/"}{print $0}'
www.baidu.com
user
test.html

RS 也支持正则

# seq -f "str%02g" 10 |sed 'n;n;a\-----' |awk 'BEGIN{RS="-+"}{print $1}'
str01
str04
str07
str10

将输出的换行符替换为+号

# seq 10 |awk 'BEGIN{ORS="+"}{print $0}'
1+2+3+4+5+6+7+8+9+10+
替换某个字符:
# tail -n2 /etc/services |awk 'BEGIN{RS="/";ORS="#"}{print $0}'
iqobject 48619#udp # iqobject
matahari 49000#tcp # Matahari Broker

NF

NF 是字段个数

# echo "a b c d e f" |awk '{print NF}'
6
打印最后一个字段:
# echo "a b c d e f" |awk '{print $NF}'
f
打印倒数第二个字段:
# echo "a b c d e f" |awk '{print $(NF-1)}'
e
排除最后两个字段:
# echo "a b c d e f" |awk '{$NF="";$(NF-1)="";print $0}'
a b c d
排除第一个字段:
# echo "a b c d e f" |awk '{$1="";print $0}'
b c d e f

NR 和 FNR

NR 统计记录编号,每处理一行记录,编号就会+1,FNR 不同的是在统计第二个文件时会重新计数。
打印行数

# tail -n5 /etc/services |awk '{print NR,$0}'
1 com-bardac-dw 48556/tcp # com-bardac-dw
2 com-bardac-dw 48556/udp # com-bardac-dw
3 iqobject 48619/tcp # iqobject
4 iqobject 48619/udp # iqobject
5 matahari 49000/tcp # Matahari Broker
打印总行数:
# tail -n5 /etc/services |awk 'END{print NR}'
5
打印第三行:
# tail -n5 /etc/services |awk 'NR==3'
iqobject 48619/tcp # iqobject
打印第三行第二个字段:
# tail -n5 /etc/services |awk 'NR==3{print $2}'
48619/tcp
打印前三行:
# tail -n5 /etc/services |awk 'NR<=3{print NR,$0}'
1 com-bardac-dw 48556/tcp # com-bardac-dw
2 com-bardac-dw 48556/udp # com-bardac-dw
3 iqobject 48619/tcp # iqobject

NR 和 FNR 的区别

# cat a
a
b
c
# cat b
c
d
e
# awk '{print NR,FNR,$0}' a b
1 1 a
2 2 b
3 3 c
4 1 c
5 2 d
6 3 e
可以看出 NR 每处理一行就会+1,而 FNR 在处理第二个文件时,编号重新计数。同时也知道 awk 处理
两个文件时,是合并到一起处理。
# awk 'FNR==NR{print $0"1"}FNR!=NR{print $0"2"}' a b
a1
b1
c1
c2
d2
e2

当 FNR==NR 时,说明在处理第一个文件内容,不等于时说明在处理第二个文件内容。
一般 FNR 在处理多个文件时会用到,下面会讲解。

ARGC 和 ARGV

ARGC 是命令行参数数量
ARGV 是将命令行参数存到数组,元素由 ARGC 指定,数组下标从 0 开始

# awk 'BEGIN{print ARGC}' 1 2 3
4
# awk 'BEGIN{print ARGV[0]}'
awk
# awk 'BEGIN{print ARGV[1]}' 1 2
1
# awk 'BEGIN{print ARGV[2]}' 1 2
2

ARGIND

ARGIND 是当前正在处理的文件索引值,第一个文件是 1,第二个文件是 2,以此类推,从而可以通
过这种方式判断正在处理哪个文件。

# awk '{print ARGIND,$0}' a b
1 a
1 b
1 c
2 c
2 d
2 e
# awk 'ARGIND==1{print "a->"$0}ARGIND==2{print "b->"$0}' a b
a->a
a->b
a->c
b->c
b->d
b->e

ENVIRON

ENVIRON 调用系统变量。

# awk 'BEGIN{print ENVIRON["HOME"]}'
/root
如果是设置的环境变量,还需要用 export 导入到系统变量才可以调用:
# awk 'BEGIN{print ENVIRON["a"]}'
# export a
# awk 'BEGIN{print ENVIRON["a"]}'
123

FILENAME

FILENAME 是当前处理文件的文件名。

# awk 'FNR==NR{print FILENAME"->"$0}FNR!=NR{print FILENAME"->"$0}' a b
a->a
a->b
a->c
b->c
b->d
b->e

忽略大小写

# echo "A a b c" |xargs -n1 |awk 'BEGIN{IGNORECASE=1}/a/'
A
a
等于 1 代表忽略大小写。
8.3.4 操作符
运算符 描述
(....) 分组
$ 字段引用
++ -- 递增和递减
+ - ! 加号,减号,和逻辑否定
* / % 乘,除和取余
+ - 加法,减法
| |& 管道,用于 getline,print 和 printf
< > <= >= != == 关系运算符
~ !~ 正则表达式匹配,否定正则表达式匹配
in 数组成员
&& || 逻辑 and,逻辑 or
?: 简写条件表达式:
expr1 ? expr2 : expr3
第一个表达式为真,执行 expr2,否则执行 expr3
= += -= *= /= %= ^= 变量赋值运算符
须知:
在 awk 中,有 3 种情况表达式为假:数字是 0,空字符串和未定义的值。
数值运算,未定义变量初始值为 0。字符运算,未定义变量初始值为空。
举例测试:
# awk 'BEGIN{n=0;if(n)print "true";else print "false"}'
false
# awk 'BEGIN{s="";if(s)print "true";else print "false"}'
false
# awk 'BEGIN{if(s)print "true";else print "false"}'
false

截取整数

# echo "123abc abc123 123abc123" |xargs -n1 | awk '{print +$0}'
123
0
123
# echo "123abc abc123 123abc123" |xargs -n1 | awk '{print -$0}'
-123
0
-123

感叹号

打印奇数行

# seq 6 |awk 'i=!i'
1
3
5
打印偶数行:
# seq 6 |awk '!(i=!i)'
2
4
6

读取第一行:i 是未定义变量,也就是 i=!0,!取反意思。感叹号右边是个布尔值,0 或空字符串为
假,非 0 或非空字符串为真,!0 就是真,因此 i=1,条件为真打印当前记录。
没有 print 为什么会打印呢?因为模式后面没有动作,默认会打印整条记录。
读取第二行:因为上次 i 的值由 0 变成了 1,此时就是 i=!1,条件为假不打印。
读取第三行:上次条件又为假,i 恢复初始值 0,取反,继续打印。以此类推…
可以看出,运算时并没有判断行内容,而是利用布尔值真假判断输出当前行。

不匹配某行

# tail /etc/services |awk '!/blp5/{print $0}'
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service
isnetserv 48128/tcp # Image Systems Network Services
isnetserv 48128/udp # Image Systems Network Services
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
matahari 49000/tcp # Matahari Broker

乘法和除法

# seq 5 |awk '{print $0*2}'
2
4
6
8
10
# seq 5 |awk '{print $0%2}'
1
0
1
0
1
打印偶数行:
# seq 5 |awk '$0%2==0{print $0}'
2
4
打印奇数行:
# seq 5 |awk '$0%2!=0{print $0}'
1
3
5

管道符使用

# seq 5 |shuf |awk '{print $0|
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值