参考文章:Linux三剑客之awk命令 - 琴酒网络 - 博客园
1. awk
1.1 简介
awk的最基本功能是在文件或者字符串中指定规则浏览和抽取信息。
通常,awk 是以行为处理单位的。awk每接收文件的一行,然后执行相应的命令,来处理文本。
awk的基本用法:
awk '{pattern + action}' {filenames}
(base) echo -e "first test line\nsecond test line" | awk '{print "hello word"}'
hello word
hello word
通过echo输出两行文本,针对每行文本使用awk输出hello world,可见一共输出了两次。
这里awk只在 {} 中使用了 print, 也可以在 {} 中使用多条命令组合
awk 输入
-
直接通过管道 | 接收标准输出的文本内容进行处理
-
直接在命令末尾指定待处理文本文件名如:/etc/passwd
(base) awk '{print $0}' /etc/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 ...
1.2 常用变量、参数
1.2.1处理规则
awk 功能是将读取的文本内容的每一行按照一定规则进行抽取、处理、输出;
-
读取每一行文本,按照指定的字段分割符(field separator),默认为空白,将每一行分割成若干字段
-
按照需求提取需要的字段:提取当前文本记录行:$0, 提取第一个字段:$1, 依次类推
-
对提取的字段按照需求进行处理: 直接输出,变量数值运算,字符拼接…
-
按照需求输出文本: 主要是指定输出字段分隔符以及每条记录的分割符
1.2.2 BEGIN和END模块
awk 处理输入文件之前允许定义一个BEGIN模块,主要可以用于初始化变量;还可以定义一个END块用于在处理完文件所有行后,进行结果输出、总结之类的操作。
实例:统计/etc/passwd的账户人数
(base) awk 'BEGIN{count=0;} {count++; print $0;} END{print "total user count: ", count}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
......
total user count: 18
1.2.3 内置变量
图为 /etc/passwd 文件的前两行内容,用来说明awk常用变量
-
FS 字段分隔符(field separator),{FS=“:”} 指定冒号分隔符
-
$0 当前记录,默认是当前处理的一行文本内容
-
$n 第n个字段的值,使用冒号分割时,$1即为字符串root
-
NF 字段数量(number field), 使用冒号分割符时,NF=7,共有7个字段
-
RS 记录分隔符(recorder separator), 默认使用换行符**\n**作为记录分隔符,此时一行文本内容,就是一条记录,一个处理单元
-
NR 记录数量,使用换行符为记录分隔符时,就是文本的所在行数
-
OFS 输出字段分隔符(output field separator)
-
ORS 输出记录分隔符(ouput recorder separator), 默认使用换行符 \n作为输出记录分隔符
1.2.4 使用实例
现在取出 /etc/passwd 的前四行说明各个变量的作用
head -n 4 /etc/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
head -n 4 /etc/passwd > passwd_4.txt
FS指定字段分割符也可以使用 -F参数进行替代
- 实例1:输出以冒号为字段分割符的最后一列内容, NF变量为字段数目,$NF即表示最后一个字段的内容
(base) awk 'BEGIN{FS=":"} {print $(NF)}' passwd_4.txt
/bin/bash
/sbin/nologin
/sbin/nologin
/sbin/nologin
(base) awk -F ":" '{print $(NF)}' passwd_4.txt
/bin/bash
/sbin/nologin
/sbin/nologin
/sbin/nologin
同时指定多个分隔符
-
实例2:输出以 冒号 和 / 为字段分割符的倒数第二列内容
(base) awk 'BEGIN{FS="[/:]"} {print $(NF-1)}' passwd_4.txt bin sbin sbin sbin (base) awk -F "[:/]" '{print $(NF-1)}' passwd_4.txt bin sbin sbin sbin
-
实例3:按照冒号分割,输出当前字段数目 NF
(base) awk -F ":" 'END {print NF}' passwd_4.txt 7
-
实例4: 输出当前文档内容并添加行号:NR
(base) awk '{print NR " " $0}' passwd_4.txt 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:输出文件第2-3行
(base) awk '{ if(NR>=2 && NR<=3) {print $0}}' passwd_4.txt bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin
-
实例6:输出第1、2个字段,字段之间通过 # 号连接,不同记录之间的分割符为两个换行符
(base) awk -F ":" 'BEGIN{OFS="#"; ORS="\n\n"} {print $1,$2}' passwd_4.txt root#x bin#x daemon#x adm#x adm#x
1.3 正则匹配
awk 正则匹配的形式为:
- 对整条记录进行匹配:awk ‘/匹配模式/{操作}’
- 对指定字段进行匹配:awk ‘字段~/匹配模式/{操作}’
下面通过实例演示awk的正则使用方式:
首先创建一个ip.txt测试文件,内容如下:
user ip
root 192.168.1.1
root 172.16.0.11
zhang1 192.168.1.12
zhang2 172.16.0.12
zhang3 192.168.0.13
li1 172.18.2.34
ma1 1234
ma2 5678
wang1 10.20.1.34
wang2 172.16.3.25
-
实例1:找出文件中所有符合用户名 ip 格式的行
(base) awk '$2~/[0-9]{1,3}\.[0-9]{1,3}\./{print $0}' ip.txt root 192.168.1.1 root 172.16.0.11 zhang1 192.168.1.12 zhang2 172.16.0.12 zhang3 192.168.0.13 li1 172.18.2.34 wang1 10.20.1.34 wang2 172.16.3.25
-
实例2:找出文件中192.168网段的文本行
(base) awk '$2~/192\.168\./{print $0}' ip.txt root 192.168.1.1 zhang1 192.168.1.12 zhang3 192.168.0.13
-
实例2: 找出文件中zhang 姓并且时192.168网段的文本
(base) awk '($1~/zhang/) && ($2~/192.168./) {print $0}' ip.txt zhang1 192.168.1.12 zhang3 192.168.0.13
1.4 字符串函数
-
字符替换
在 info 中查找满足正则表达式, /[0-9]+/ 用”!”替换,并且替换后的值,赋值给 info 未
给 info 值,默认是$0awk 'BEGIN{info="this is a test2010test!";gsub(/[0-9]+/,"!",info);print info}' this is a test!test!
-
查找
(base) awk 'BEGIN{info="this is a test2010test!";print index(info,"test")?"ok":"no found";}' ok
-
截取
(base) awk 'BEGIN{info="this is a test2010test!";print substr(info,4,10);}' s is a tes