awk

在 Linux/UNIX 系统中,awk 是一个功能强大的编辑工具,逐行读取输入文本,并根据指定的匹配模式进行查找,对符合条件的内容进行格式化输出或者过滤处理,可以在无交互的情况下实现相当复杂的文本操作,被广泛应用于 Shell 脚本,完成各种自动化配置任务。

AWK是一种处理文本文件的语言,是一个强大的文本分析工具。之所以叫 AWK 是因为其取了三位创始人 Alfred Aho,Peter Weinberger, 和 Brian Kernighan 的 Family Name 的首字符。

语法格式:

语法格式解释:

语法格式 含义
BEGIN{} 正式处理数据之前执行
pattern 匹配模式
{commands} 处理命令,可能多行
END{} 处理完所有匹配数据后执行

awk内置变量

内置变量 含义
$0 整行内容
$1~$n 当前行的第1-n个字段
NF 当前行的字段个数,也就是有多少列
NR 当前行的行号,从1开始计数
FNR 多文件处理时,每个文件行号单独计数都是从0开始
FS 输入字段分隔符,不指定则默认以空格或tab键分隔
RS 输入行分隔符,默认回车换行
OFS 输出字段分隔符,默认为空格
ORS 输出行分隔符,默认回车换行
FILENAME 当前输入的文件名字
ARGC 命令行参数个数
ARGV 命令行参数数组

示例

以下所有示例文件为/etc/passwd,请将其拷贝一份使用

# 打印整行内容
awk '{print $0}' passwd# 使用":"号作为分隔符,输出第一个字段
awk 'BEGIN{FS=":"}{print $1}' passwd
->root
->bin
->daemon
->adm
->lp
->sync
->shutdown
->...# 输出行号
awk '{print NR}' passwd# 多个文件行号单独计数
awk '{print FNR}' passwd file2# 指定行分隔符
echo "hello-world-hello-linux-hello-java" | awk 'BEGIN{RS="-"}{print $0}'
->hello
->world
->hello
->linux
->hello
->java
-># 指定输出字段分隔符
awk 'BEGIN{FS=":";OFS=":"}{print NR,$1}' passwd
->1:root
->2:bin
->3:daemon
->4:adm
->5:lp
->...

printf格式化输出

格式符 含义
%s 打印字符串
%d 打印十进制数
%f 打印一个浮点数
%x 打印十六进制数
%o 打印八进制数
%e 打印数字的科学计数法形式
%c 打印单个字符的ASCII码
- 左对齐
+ 右对齐
# 显示8进制在前面加0,显示16进制在前面加0x

示例

# 以字符串格式打印第1个字段,以":"作为分隔符
awk 'BEGIN{FS=":"}{printf "%st",$1}' passwd
->root  bin daemon  adm lp ...# 以字符串格式打印第1个字段和对应行号,输出格式为"行号:字段内容"
awk 'BEGIN{FS=":"}{printf "%d:%sn",NR,$1}' passwd
->1:root
->2:bin
->3:daemon
->4:adm
->5:lp
->...# 左对齐
# 在不指定位数的情况下默认左对齐,指定位数后为右对齐(必须指定位数)
awk 'BEGIN{FS=":"}{printf "%10d:%sn",NR,$1}' passwd
->         1:root
->         2:bin
->         3:daemon
->         4:adm
->         5:lp
->...awk 'BEGIN{FS=":"}{printf "%-10d:%sn",NR,$1}' passwd
->1         :root
->2         :bin
->3         :daemon
->4         :adm
->5         :lp
->...

两种匹配模式

模式 含义
正则 按正则表达式匹配
关系运算 按关系运算匹配

关系运算符:

  • < : 小于
  • > : 大于
  • <= : 小于等于
  • >= : 大于等于
  • == : 等于
  • != : 不等于
  • ~ : 匹配正则表达式
  • !~ : 不匹配正则表达式

布尔运算符:

  • || : 或
  • && : 与
  • ! : 非
# 匹配文件行中含有root字符串的所有行
awk 'BEGIN{FS=":"}/root/{print $0}' passwd
->root:x:0:0:root:/root:/bin/bash
->operator:x:11:0:operator:/root:/sbin/nologin# 匹配第3个字段小于50的所有行信息
awk 'BEGIN{FS=":"}$3<50{print $0}' passwd# 匹配文件中包含mail或ftp的所有行信息
awk 'BEGIN{FS=":"}/mail/||/ftp/{print $0}' passwd
->mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
->ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin# 匹配文件中第3个字段小于50并且第4个字段大于50的所有行信息
awk 'BEGIN{FS=":"}$3<50 && $4 > 50{print $0}' passwd
->games:x:12:100:games:/usr/games:/sbin/nologin# 匹配文件中第3个字段小于50并且第7个字段匹配/bin/bash的所有行信息
awk 'BEGIN{FS=":"}$3<50 && $7 ~ //bin/bash/{print $0}' passwd
->root:x:0:0:root:/root:/bin/bash

awk表达式

# 统计空白行数目
awk '/^$/{sum++}END{print sum}' /etc/services
->17# 统计一下学生成绩总分和平均分,报表形式展示
姓名    语文    数学    英语    物理
张三     80     60      85      90
李四     85     65      80      75
王五     70     60      85      90
李华     65     80      84      91
王八     90     90      95      90awk 'BEGIN{printf "%-8s%-5s%-5s%-5s%-5s%-5s%-8sn","姓名","语文","数学","英语","物理","总分","平均分"}{total=$2+$3+$4+$5;avg=total/4;printf "%-8s%-8d%-6d%-8d%-7d%-5d%0.2fn",$1,$2,$3,$4,$5,total,avg}' stu.txt姓名      语文   数学   英语   物理   总分   平均分
张三      80      60    85      90     315  78.75
李四      85      65    80      75     305  76.25
王五      70      60    85      90     305  76.25
李华      65      80    84      91     320  80.00
王八      90      90    95      90     365  91.25

条件语句和循环语句

# 条件语句
if (条件表达式1){action1
}else if (条件表达式2){action2
}else{action3
}# 以":"为分隔符,如果第3个字段小于50,打印小于50,如果等于50则打印等于50,否则打印大于50
awk 'BEGIN{FS=":"}{if($3<50){print "小于50" }else if($3==50){ print "等于50"}else{print "大于50"}}' passwd# 我们可以将命令保存在一个文件(eg:oper.awk,后缀不硬性要求哦!)中使用-f选项引入
awk -f oper.awk passwd# 循环语句 while
while(条件表达式){action
}# 循环语句 do while
do{action
}while(条件表达式)# 循环语句 for
for(初始化计数器;测试计数器;变更计数器){action
}# 计算1+2+3+...+100的和。
awk 'BEGIN{do{i++;sum+=i;}while(i<100)print sum}'
awk 'BEGIN{while(i<100){i++;sum+=i;}print sum}'
awk 'BEGIN{for(i=0;i<=100;i++){sum+=i;}print sum}'

字符串函数

函数名 含义 函数返回值
length(str) 计算字符串长度 整数长度值
index(str1,str2) 在str1中查找str2的位置 位置索引,从1计数
tolower(str) 转换为小写 转换后的小写字符串
toupper(str) 转换为大写 转换后的大写字符串
substr(str,m,n) 从str的m个字符开始,截取n位 截取后的子串
split(str,arr,fs) 按fs切割字符串,结果保存在arr中 切割后的子串个数
match(str,RE) 在str中按照RE查找,返回位置 返回索引位置
sub(RE,RepStr,str) 在str中搜索符合RE的子串,将其替换为RepStr,只替换第一个 替换的个数
gsub(RE,RepStr,str) 在str中搜索符合RE的子串,将其替换为RepStr,替换所有 替换的个数

示例

# 以:为分隔符,返回文件每行中每个字段的长度
awk 'BEGIN{FS=":"}{for(i=1;i<=NF;i++){if(i==NF){printf "%d",length($i)}else{printf "%d:",length($i)}}print ""}' passwd# 搜索字符串"I am a student"中student子串的位置
echo "I am a student" | awk '{print index($0,"student")}'
->8

awk常用选项

选项 含义
-v 参数传递
-f 指定脚本文件
-F 指定分隔符
-V 查看awk版本号
# 使用-v引用外部变量
num1=100
num2=200
awk -v var1="$num1" -v var2="$num2" 'BEGIN{print var1+var2}'

数组

awk中数组使用小括号包围起来,每一项之间使用空格分隔,如:arr=("one" "two" "three" "four" "five").在awk中数组下标从1开始,需要注意哦~。 awk可以使用关联数组这种数据结构,索引可以是数字或字符串。awk关联数 组也不需要提前声明其大小,因为它在运行时可以自动的增大或减小。

# 统计主机上所有的TCP,按照TCP状态进行分类
netstat -an | grep tcp | awk '{array[$6]++}END{for(item in array){print item,array[item]}}'
->LISTEN 8
->ESTABLISHED 26

awk文件处理

awk 可以直接处理目标文件,也可以通过“-f”读取脚本对目标文件进行处理。

(1) awk 比较倾向于将一行分成多个“字段”然后再进行处理,且默认情况下字段的分隔符为空格或者 tab 键。awk 执行结果可以通过 print 的功能将字段数据打印显示。在使用 awk 命令的过程中,可以使用

逻辑操作符如下所示:

*“&&”,表示“与”* *“||”,表示“或”* *“!”,表示“非”*

简单的数学运算如下:

+、-、*、/、%、^分别 表示加、减、乘、除、取余和乘方

(2)在 Linux 系统中/etc/passwd 是一个非常典型的格式化文件,各字段间使用“:”作为分隔符隔开,Linux 系统中的大部分日志文件也是格式化文件,从这些文件中提取相关信息是运维的日常工作内容之一。

例如:需要查找出/etc/passwd 的用户名、用户 ID、组 ID 等列, 执行以下 awk 命令即可。

[root@localhost ~]# awk -F ':' '{print $1,$3,$4}' /etc/passwd
root 0 0
bin 1 1
daemon 2 2
adm 3 4
lp 4 7
sync 5 0
shutdown 6 0
halt 7 0
mail 8 12
operator 11 0
games 12 100
ftp 14 50
//省略部分内容

awk 从输入文件或者标准输入中读入信息,与 sed 一样,信息的读入也是逐行读取的。不同的是 awk 将文本文件中的一行视为一个记录,而将一行中的某一部分(列)作为记录中的一个字段(域)。为了操作这些不同的字段,awk 借用 shell 中类似于位置变量的方法, 用$1、$2、$3„顺序地表示行(记录)中的不同字段。另外 awk 用$0 表示整个行(记录)。不同的字段之间是通过指定的字符分隔。awk 默认的分隔符是空格。awk 允许在命令行中用“-F 分隔符”的形式来指定分隔符。因此,上述示例中,awk 命令对/etc/passwd 文件的处理过程如图 所示:

awk工作原理图

(3)awk 包含几个特殊的内建变量(可直接用):

  • FS:指定每行文本的字段分隔符,默认为空格或制表位。
  • NF:当前处理的行的字段个数。
  • NR:当前处理的行的行号(序数)。
  • $0:当前处理的行的整行内容。
  • $n:当前处理行的第 n 个字段(第 n 列)。
  • FILENAME:被处理的文件名。
  • RS:数据记录分隔,默认为n,即每行为一条记录。

用法示例

(1)按行输出文本

输出所有内容

[root@localhost opt]# awk '{print}' test.txt      //输出所有内容,等同于 cat test.txt

或者

[root@localhost opt]# awk '{print $0}' test.txt      //输出所有内容,等同于 cat test.txt

输出1-3行内容

[root@localhost opt]# awk 'NR==1,NR==3{print}' test.txt    //输出第 1~3 行内容
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

或者

[root@localhost opt]# awk '(NR>=1)&&(NR<=3){print}' test.txt     //输出第 1~3 行内容
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

输出以root 开头的行

[root@localhost opt]# awk '/^root/{print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash

输出以 nologin 结尾的行

[root@localhost opt]# awk '/nologin$/{print}' /etc/passwd
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
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
libstoragemgmt:x:998:996:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
colord:x:997:995:User for colord:/var/lib/colord:/sbin/nologin
saslauth:x:996:76:Saslauthd user:/run/saslauthd:/sbin/nologin
rtkit:x:172:172:RealtimeKit:/proc:/sbin/nologin
pulse:x:171:171:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
chrony:x:995:991::/var/lib/chrony:/sbin/nologin
rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
ntp:x:38:38::/etc/ntp:/sbin/nologin
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
usbmuxd:x:113:113:usbmuxd user:/:/sbin/nologin
geoclue:x:994:989:User for geoclue:/var/lib/geoclue:/sbin/nologin
qemu:x:107:107:qemu user:/:/sbin/nologin
radvd:x:75:75:radvd user:/:/sbin/nologin
setroubleshoot:x:993:988::/var/lib/setroubleshoot:/sbin/nologin
sssd:x:992:987:User for sssd:/:/sbin/nologin
gdm:x:42:42::/var/lib/gdm:/sbin/nologin
gnome-initial-setup:x:991:986::/run/gnome-initial-setup/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
dhcpd:x:177:177:DHCP server:/:/sbin/nologin

统计以/bin/bash 结尾的行数,等同于 grep -c "/bin/bash$" /etc/passwd

[root@localhost opt]# awk 'BEGIN{X=0};//bin/bash$/{x++};END{print x}' /etc/passwd
11

统计以空行分隔的文本段落数

[root@localhost ~]# awk 'NEGIN{RS=""};END{print NR}' /etc/passwd
52

(2)按字段输出文本

输出每行中(以空格或制表位分隔)的第 3 个字段

[root@localhost ~]# awk '{print $3}' /etc/passwdManagement:/:/sbin/nologinbus:/:/sbin/nologinpolkitd:/:/sbin/nologinforcolord:/var/lib/colord:/sbin/nologinDaemon:/var/run/pulse:/sbin/nologinUser:/var/lib/nfs:/sbin/nologin
User:/var/lib/nfs:/sbin/nologinbygeoclue:/var/lib/geoclue:/sbin/nologinsssd:/:/sbin/nologinStack:/var/run/avahi-daemon:/sbin/nologin[root@localhost ~]#

输出每行中的第 1、3 个字段

[root@localhost ~]# awk '{print $1,$3}' /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
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync

输出密码为空的用户的shadow 记录

[root@localhost ~]# awk -F ":" '$2==""{print}' /etc/shadow

或者

[root@localhost ~]# awk 'BEGIN{FS=":"};$2==""{print}' /etc/shadow

输出以冒号分隔且第 7 个字段中包含/bash 的行的第 1 个字段

[root@localhost ~]# awk -F ":" '$7~"/bash"{print $1}' /etc/passwd
root
shan
lisi
wangwu
zhangsan
liuliu
c
xiao
jing
tol
jiji
sfya

输出包含 8 个字段且第 1 个字段中包含 nfs 的行的第 1、2 个字段

[root@localhost ~]# awk '($1~"nfs")&&(NF==8){print $1,$2}' /etc/services
nfs 2049/tcp
nfs 2049/udp
nfs 2049/sctp
netconfsoaphttp 832/tcp
netconfsoaphttp 832/udp
netconfsoapbeep 833/tcp
netconfsoapbeep 833/udp

输出第 7 个字段既不为/bin/bash 也不为/sbin/nologin 的所有行

[root@localhost ~]# awk -F ":" '($7!="/bin/bash")&&($7!="/sbin/nologin"){print}' /etc/passwd
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt

*(3)通过管道、双引号调用 Shell 命令*

调用wc -l 命令统计使用bash 的用户个数,等同于 grep -c "bash$" /etc/passwd

[root@localhost ~]# awk -F : '/bash$/{print | "wc -l"}' /etc/passwd
12

调用w 命令,并用来统计在线用户数

[root@localhost ~]# awk 'BEGIN{while("w" | getline)n++;{print n-2}}'
4

调用hostname,并输出当前的主机名

[root@localhost ~]# awk 'BEGIN{"hostname" | getline;print $0}'
localhost.localdomain

awk 内嵌正则 提取字符串_干货-Shell编程文本处理三剑客之-awk相关推荐

  1. awk 内嵌正则 提取字符串_使用awk提取字符串中的数字或字母

    1.提取字符串中的数字 $ echo 'dsFUs34tg*fs5a%8ar%$#@' |awk -F "" ' { for(i=1;i<=NF;i++) { if ($i ...

  2. awk处理带有空格的字符串_五分钟入门文本处理三剑客grep awk sed

    介绍 grep awk sed是Linux下文本处理常用的命令,能完成很多神奇的操作,今天就分享一下这三个命令最常见的用法 grep 使用一般有如下两种形式 第一种形式 grep [option] [ ...

  3. 正则表达式 以字符串开头_干货-Shell编程之正则表达式

    正则表达式 一.正则表达式的定义 正则表达式又称正规表达式.常规表达式.在代码中常简写为 regex.regexp 或 RE. 1.正则表达式是使用单个字符串来描述.匹配一系列符合某个句法规则的字符串 ...

  4. python用方括号提取字符中的数值_Python使用re模块正则提取字符串中括号内的内容示例...

    Python使用re模块正则提取字符串中括号内的内容示例 本文实例讲述了Python使用re模块正则提取字符串中括号内的内容操作.分享给大家供大家参考,具体如下: 直接上代码吧: # -*- codi ...

  5. Python使用re模块正则提取字符串中括号内的内容示例

    Python使用re模块正则提取字符串中括号内的内容示例 这篇文章主要介绍了Python使用re模块正则提取字符串中括号内的内容,结合实例形式分析了Python使用re模块进行针对括号内容的正则匹配操 ...

  6. linux sed 正则提取字符串,Shell中使用grep、sed正则提取和替换字符串

    Linux中使用grep正则提取字符串 echo office365 | grep -P '\d+' -o find . -name "*.txt" | xargs grep -P ...

  7. java 正则 提取数字_java使用正则提取字符串中的数字(例如提取短信中的验证码)详解...

    使用java正则可以很方便的从字符串中提取符合条件的内容. 1.提取字符串中所有的手机号: private void getPhoneNum(String smsBody) { Pattern pat ...

  8. 1008day1:列表-字符串基础知识、正则提取字符串小数、python数据类型、判断为假的方法、格式判断if elif elif else、字符串遍、计算器、提取str字母、斐波那契数列、水仙花数

    文章目录 一.提取字符串里面的小数:正则 二.Python数据类型 三.== 字符串:str基础知识 == 四.整型及浮点型 五.判断为假的方法 六.判断格式 七.循环:字符串遍历 六.循环1~100 ...

  9. 正则提取字符串中内容

    有的时候,会有这样的需求,给定一个特定结构的字符串,需要将其中的可变部分提取出来,例如,有一段关于优惠券的话术"满199元减20元",其中,199是使用优惠券的条件,而20则是具体 ...

最新文章

  1. 对象序列化与反序列化
  2. 如果某一运行的服务在/var/lock/subsys
  3. java正则过滤特殊字符
  4. A - System Administrator CodeForces - 245A(水题)
  5. win10子系统 php,启用 Win10 的 Linux 子系统
  6. SpringMVC学习(二)使用注解开发SpringMVC
  7. 回忆有自己的场景,有两种角度
  8. 多人麻将源码 html5,新版大众麻将 H5版
  9. Scratch3.0安装教程
  10. springboot 防止xss 和sql 注入 改写 http 请求 getParameter,getParameterValues,getHeader等方法 有点东西
  11. 闪购网站Gilt从Rails迁移到Scala
  12. JXplorer 的简单使用
  13. 链表结点定义---指针指向结点
  14. JumpServer(堡垒机)开源版本图文详解
  15. 语法体系:揭秘同位语从句day9
  16. iOS H5 获取麦克风权限
  17. 电到底是怎么工作的?
  18. kicad 输出Gerber文件
  19. Pandas的学习之——使用Pandas进行描述性统计
  20. 好代码 ,坏代码:你的代码和其他工程师的代码

热门文章

  1. CTF(Pwn) Rop + ret2libc 题型 常规解法思路 (初级)
  2. 学习CTF(二进制安全)一个月多的奇妙冒险~;
  3. oracle 整个表空间迁移,ORACLE表批量迁移表空间
  4. Python基础教程:如何打破while循环?
  5. python教程:循环(while和for)
  6. Python argparse模块基本用法
  7. Python-functools (reduce,偏函数partial,lru_cache)
  8. mysql数据库前端缓存_MySQL数据库性能优化--缓存参数优化
  9. python 测试multiprocessing多进程
  10. 【中级软考】什么是“敏捷过程的开发方法(敏捷方法agile)“(极限编程XP、特征驱动开发FDD、并列争球法Scrum、水晶法Crystal、开放源码法、自适应软件开发 ASD方法)