awk 截取部分字符串_干货-Shell编程文本处理三剑客之-awk

awk

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

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

语法格式:

25fce9aa0409ce5dd06d557f6eefe05b.png

语法格式解释:

语法格式含义
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表达式

266db04350c04ef829fcb9997d1cc915.png
# 统计空白行数目
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      90

awk '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 文件的处理过程如图 所示:

d2b622ee02b8f527b35b43d22c355b83.png
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/passwd












Management:/:/sbin/nologin



bus:/:/sbin/nologin



polkitd:/:/sbin/nologin




for


colord:/var/lib/colord:/sbin/nologin


Daemon:/var/run/pulse:/sbin/nologin

User:/var/lib/nfs:/sbin/nologin
User:/var/lib/nfs:/sbin/nologin

by

geoclue:/var/lib/geoclue:/sbin/nologin



sssd:/:/sbin/nologin




Stack:/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
表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
相关推荐
©️2020 CSDN 皮肤主题: 1024 设计师:白松林 返回首页