pmliang avatar

AWK常见用法(一)

pmliang

Published: 20 May 2018 › Updated: 20 May 2018AWK常见用法(一)

AWK常见用法(一)

一、初识AWK

AWK有其他的衍生版本,比如nawkgawk,在Linux发行版里,默认使用的是gawk:

# ls -l `which awk`
lrwxrwxrwx. 1 root root 4 5   9 20:25 /usr/bin/awk -> gawk

二、AWK的工作流程

  • AWK是按行处理文本,将行按照某一分隔符进行分割,其中分割之后的第一部分为$1,第二部分为$2,依次类推,其中$0表示整行,超过10的要将数字用括号括起来,比如$(10)
  • AWK默认的分隔符是空格和tab,其中操作命令必须写在{}里面,语法:
awk '/模式/{print $1}' file     //模式支持正则表达式,只对含有该模式的行进行操作
  • 可以使用-F选项指定分隔符:
awk -F: '/模式/{print $1}' file

三、常见操作符的使用(例子中passwd文件使用/etc/passwd文件的前6行)

常见的操作符有:~!~==!=><++--

  1. ~!~表示包含和不包含:
# awk -F: '$1~/ro/{print $0}' passwd 
root:x:0:0:root:/root:/bin/bash
  1. ==!=表示严格的等于和不等于:
# awk -F: '$3==1{print $0}' passwd 
bin:x:1:1:bin:/bin:/sbin/nologin
# awk -F: '{$3++;print $3}' passwd 
1
2
3
4
5
6
  1. 其他的一些操作符同理,两个以上的条件需要使用连接符&&||

四、AWK中 BEGIN 和 NED 的用法

  1. BEGIN中的命令是在AWK读取文本的第一行之前进行操作:
# awk -F: 'BEGIN{print "用户名"}{print $1}' passwd 

root
bin
daemon
adm
lp
sync
  1. END中的命令是在读取完最后一行之后进行的操作:
# awk -F: '{print $1}END{print "结束"}' passwd 
root
bin
daemon
adm
lp
sync

  1. BEGIN和END可以同时出现,也可以单独出现,BEGIN中可以定义变量:
# awk -F: 'BEGIN{a=1}{print a}' passwd 
1
1
1
1
1
1

如何没有预先定义变量的话,在后面也是可以引用的,只不过这个变量的值为空。引用变量的时候不加$
END中也可以进行最终的计算:

# awk -F: 'BEGIN{sum=0}{sum+=$3}END{print "所有UID的和为:"sum}' passwd 
UID15

或者不预先定义变量:

# awk -F: '{sum+=$3}END{print "所有UID的和为:"sum}' passwd 
UID15

五、AWK中常见内置变量的用法

  1. FS代表分隔符:
# awk 'BEGIN{FS=":"}{print $1}' passwd 
root
bin
daemon
adm
lp
sync
  1. OFS为打印输出的分隔符,默认的是空格:
# awk 'BEGIN{FS=":";OFS="---"}{print $1,$2}' passwd 
root---x
bin---x
daemon---x
adm---x
lp---x
sync---x
  1. NF的值表示将每一行按照FS指定的分隔符分为多少段:
# awk 'BEGIN{FS=":"}{print NF}' passwd 
7
7
7
7
7
7

如果要打印每一行的最后一段,可以使用以下用法:

# awk 'BEGIN{FS=":"}{print $NF}' passwd 
/bin/bash
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/bin/sync
  1. 前面提到过,AWK是将文件按行进行处理,那么AWK是如何分别每一行的呢?使用的就是RS的值,默认为\n:
# cat test.txt 
1,: 2,: 3,:
# awk -F[:,] 'BEGIN{RS=" "}{print $2,$3}' test.txt 
 
 
 
  1. ORS变量的值决定输出行的分隔符,默认的为\n
# awk 'BEGIN{ORS="---"}{print $0}' passwd 
root:x:0:0:root:/root:/bin/bash---bin:x:1:1:bin:/bin:/sbin/nologin---daemon:x:2:2:daemon:/sbin:/sbin/nologin---adm:x:3:4:adm:/var/adm:/sbin/nologin---lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin---sync:x:5:0:sync:/sbin:/bin/sync---
  1. FILENAME变量的值为当前操作文件的文件名:
# awk -F: '{print FILENAME}' passwd 
passwd
passwd
passwd
passwd
passwd
passwd
  1. NR变量的值表示当前正在操作的行号:
# awk -F: '{print NR}' passwd 
1
2
3
4
5
6

如果这里将行分隔符RS赋值为-,验证NR的值:

# awk 'BEGIN{RS="-"}{print NR}' passwd 
1
  1. FNR也表示当前操作的行号,不同的是,当对一个文件进行操作的时候FNRNR的值是一样的。当对两个文件进行操作时,FNRNR的值是不一样的:
# awk -F: '{print NR,$1,FNR}' passwd shadow 
1 root 1
2 bin 2
3 daemon 3
4 adm 4
5 lp 5
6 sync 6
7 root 1
8 bin 2
9 daemon 3
10 adm 4
11 lp 5
12 sync 6

六、判断和循坏语句

  1. if语句:
    语法,如果语句没有使用{},则要使用;分隔
if(1){1}else if(2){2}else{3}
if(1)1;else if(2)2;else3
# awk -F: '{if($3==0){print $1"是root"}else if($3>=1000){print $1"是普通用户"}else{print $1"是系统用户"}}' passwd 
rootroot
bin
daemon
adm
lp
sync
  1. for循坏语句:
awk -F: '{for(i=1;i<=NF-5;i++){print $i}}' passwd 
root
x
bin
x
daemon
x
  1. while循坏语句:
# awk -F: '{print "------------";i=1;while(i<=NF){print $i;i++}}' passwd 
------------
root
x
0
0
root
/root
/bin/bash
------------
bin
x
1
1
bin
/bin
/sbin/nologin
------------
daemon
x
2
2
daemon
/sbin
/sbin/nologin
  1. 循坏控制语句break
    break只能用在循环语句中,作用是跳出当前循环,继续下一循环
# echo -e "1 2 3 4 1\n5 6 7" | awk '{for(i=1;i<=NF;i++){if($i>=2){break}print $i}}'
1
  1. 循环控制语句continue:如果遇到continue,continue后面的语句不再执行,继续下一个循环
# echo -e "1 2 3 4 1\n5 6 7" | awk '{for(i=1;i<=NF;i++){if($i>=2){continue}print $i}}'
1
1
  1. 循环控制语句next:遇到next,跳出循环,继续下移循环,在循环语句中next和break语句效果一样。区别在于,break和continue语句只能用于循环语句,next语句还可以用于其他语句,以下例子用于判断语句
# echo -e "1 2 3 4 1\n5 6 7 1" | awk '{if($2<=2){next}print $0}'
5 6 7 1
# awk -F: 'NR==FNR{print NR,FILENAME,FNR;next}{print NR,FILENAME,FNR}' passwd shadow 
1 passwd 1
2 passwd 2
3 passwd 3
4 shadow 1
5 shadow 2
6 shadow 3

七、AWK中数组的使用

  1. 手动定义数组
# echo '' | awk '{aa[1]=1;aa[2]=2;aa["b"]="b";print aa[1]}'
1
  1. 读取文件
# awk -F: '{for(i=1;i<=NF;i++){a[i]=$i;print a[1];break}}' passwd 
root
bin
daemon
# cat c1
01 
02 
03 广
04 
# cat c2
01 beijing
02 shanghai
03 guangzhou
04 shenzhen
# awk 'NR==FNR{a[$1]=$0}NR!=FNR{print a[$1],$2}' c1 c2
01  beijing
02  shanghai
03 广 guangzhou
04  shenzhen

八、AWK中常见函数的使用

  1. subgsub函数:用来替换
# cat test.txt 
tom bob mary tom
bob tom mary tom
# awk '{sub("tom","TOM");print}' test.txt 
TOM bob mary tom
bob TOM mary tom

但是只替换了每行的第一个,要想替换所有的,使用gsub函数:

# awk '{gsub("tom","TOM");print}' test.txt 
TOM bob mary TOM
bob TOM mary TOM

只替换最后一个:

# awk '{gsub("tom","TOM",$NF);print}' test.txt 
tom bob mary TOM
bob tom mary TOM
  1. length函数用来计算字符串长度
# awk -F: '{print $1,length($1)}' passwd 
root 4
bin 3
daemon 6
  1. substr函数用来截取一段数据
# awk -F: '{print substr($1,2)}' passwd 
oot
in
aemon
# awk -F: '{print substr($1,2,2)}' passwd 
oo
in
ae
  1. match函数的使用,从字符串中匹配满足某种格式的位置
# awk -F: '{xx=match($1,"oo");print xx}' passwd 
2
0
0

match中有两个变量,RSTART可以获取到match得到的值,RLENGTH表示的是match中满足格式的字符创的长度,一般会结合substr截取我们所需要的数据:

# awk -F: '{xx=match($1,"oo");print xx,RSTART,RLENGTH}' passwd 
2 2 2
0 0 -1
0 0 -1
  1. split函数的使用:split("原始字符串",数组名,<分隔符>)
# echo '' | awk '{split("2018-05-20",xx,"-");print xx[1],xx[2],xx[3]}'
2018 05 20
# awk '{split($0,xx,":");print xx[1]}' passwd 
root
bin
daemon
  1. getline函数可以让我们使用操作系统命令,也可以读取另一个文件内容
# awk '{getline;print $0}' c1
02 
04 

可以看到getline将本文件的下一行赋值给当前的$0

# awk '{getline xx;print $0,xx}' c1
01  02 
03 广 04 

在这里将下一行的值赋值给了getline后的变量xx,并没有影响当前的$0

getline < file:该用法读取file文件的一行赋值给当前的$0
getline xx < file:该用法读取file文件的一行赋值给变量xx

# awk '{getline xx< "c2";print xx,$2}' c1
01 beijing 
02 shanghai 
03 guangzhou 广
04 shenzhen 
# echo '' | awk '{"date"|getline xx;print xx}'
2018 05 20  19:57:04 CST
# echo '' | awk '{while("ls /boot"|getline xx) print xx}'
config-3.10.0-327.el7.x86_64
grub2
initramfs-0-rescue-ba7506401e184ceea617517542f6b7c7.img
initramfs-3.10.0-327.el7.x86_64.img
initrd-plymouth.img
symvers-3.10.0-327.el7.x86_64.gz
System.map-3.10.0-327.el7.x86_64
vmlinuz-0-rescue-ba7506401e184ceea617517542f6b7c7
vmlinuz-3.10.0-327.el7.x86_64

# echo '' | awk '{print "请输入:";getline name<"/dev/tty";print "你好:" name}'

tom
:tom

九、AWK的格式化输出

  1. printf不带换行符
# awk -F: '{printf "%-8s|%-5d\n",$1,$3}' passwd 
root    |0    
bin     |1    
daemon  |2

其中%-8s中的-8表示显示宽度为8个字符,-表示左对齐,+号表示右对齐
%d显示的整数
%f显示的是浮点数,%10.5f表示总共显示十位。小数点后显示5位
%e用科学计数法显示

# echo '' | awk '{printf "%d\n",3*3.5}'
10
# echo '' | awk '{printf "%f\n",3*3.5}'
10.500000
# echo '' | awk '{printf "%-.10f\n",10/3}'
3.3333333333
# echo '' | awk '{printf "%e\n",3*3.5}'
1.050000e+01

Leave AWK常见用法(一) to:

Written by

Read more #linux posts


Best Posts From pmliang

We have not curated any of pmliang's posts yet. But you can encourage our curation team to review posts by visiting them regularly and by referring other readers. Because we give priority to frequently read content.

More Posts From pmliang