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 
所有UID的和为:15

或者不预先定义变量:

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

五、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;else语句3
# awk -F: '{if($3==0){print $1"是root"}else if($3>=1000){print $1"是普通用户"}else{print $1"是系统用户"}}' passwd 
root是root
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

扫描二维码关注公众号,回复: 1437407 查看本文章

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

猜你喜欢

转载自blog.csdn.net/qq_28451255/article/details/80385362
今日推荐