三剑客-awk

1948 字
10 分钟
三剑客-awk

三剑客-awk#

[TOC]


awk#

概述#

每个的特点不同,有一定的差异

格式#

  • 也是一行一行的读,没有默认输出
  • 直到读到文件的最后一行就完事了
  • 默认支持扩展正则

1)⭐取行#

  • NR是awk的内置变量,存储着每行的行号
  • $0 表示当前行的内容 也就是整行输出

模糊匹配#

📌 awk语法:

Terminal window
awk '/正则/' file
  • awk默认支持扩展正则

🌰 案例:输出包含root或者adm的行

Terminal window
[root@oldboyedu ~]# awk '/root|adm/' passwd.txt
root:x:0:0:root:/root:/bin/bash
adm:x:3:4:adm:/var/adm:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin

🌰 案例:区间范围

Terminal window
[root@oldboyedu ~]# awk '/root/,/adm/' passwd.txt
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
operator:x:11:0:operator:/root:/sbin/nologin

2)⭐取列#

  • 取倒数第二列:$(NF-1)
  • 这两列是没有任何关系的,单独的两列
  • 别忘了{ }里面加 print
  • 1是文件中的第一列,1 是文件中的第一列,2 文件中的第二列
  • , 逗号awk内置变量,存储着空格
    • '{print $4,$NF}'
    • 认识双引号,里面的内容原样输出
  • '{print $4" "$NF}'
    • 双引号取代了原本的,逗号

输出对齐#

Terminal window
[root@oldboyedu ~]# ll | awk '{print $4,$NF}' | column -t
# column -t 实现对齐输出
[root@oldboyedu ~]# ll | awk '{print $4"\t"$NF}'
# \t 相当于是取代了,逗号
  • 别忘了中间的双引号
  • "\t" 相当于是取代了,逗号

” ” 双引号#

  • 输出自定义内容
  • ” ” 双引号里面的东西都可以被输出

  • 原理同上,双引号取代了原本的,逗号
  • 双引号里面的内容被原样输出
Terminal window
[root@oldboyedu ~]# cat 4.txt
1.txt
2.txt
3.txt
[root@oldboyedu ~]# awk '{print $1}' 4.txt
1.txt
2.txt
3.txt
[root@oldboyedu ~]# awk '{print "touch "$1}' 4.txt
touch 1.txt
touch 2.txt
touch 3.txt
[root@oldboyedu ~]# awk '{print "touch "$1";cd /etc"}' 4.txt
touch 1.txt;cd /etc
touch 2.txt;cd /etc
touch 3.txt;cd /etc

⭐awk -F (指定分隔符)#

  • 空白字符:空格,连续的空格,tab键
  • -F 和分隔符 ’ : ’ 之间不留空格也是可以的
  • -F后面匹配的字符可以用正则表达式

可是我们不要后面的 / 斜杠,那怎么办?

因为我们知道-F后面的分隔符是可以用正则表达式的,所以我们可以匹配不同的符号,从而进行分割

Terminal window
[root@oldboyedu ~]# awk -F '[ /]' file
# 中括号,这几个字符中的一种,空格或/ 斜杠

  • 这里是以 空格 或者 / 任意一个字符为分隔符

可以明显感觉,还是很麻烦,怎么让连续的空格变为一个呢,+ #连续出现一次及以上

Terminal window
[root@oldboyedu ~]# awk -F '[ /]+' file
# 这样就可以了

⚠️ 特别要注意这个+号,因为有时候它前面的空格不止一个,而且他们还都是连续的空格,所以很多时候这个+号是很有必要的

📌 这个+号是很有必要的

passwd.txt也是同理

  • -F':' #只以冒号进行分隔(不彻底)
  • -F'[:/]' #只要匹配到了其中一个字符就会切一刀,切的刀数太频繁了
  • -F'[:/]+' #后面来一个**+号**,完美解决这个问题!

🌰 案例:取出test字符串

Terminal window
[root@oldboyedu ~]# echo -+=:/oldboy_=+-:test-/-=oldgirl | awk -F "[-+=:/_]" '{print $11}'
test
# 没加+号,分隔符匹配次数多,test在第11列
[root@oldboyedu ~]# echo -+=:/oldboy_=+-:test-/-=oldgirl | awk -F "[-+=:/_]+" '{print $3}'
test
# 加了+号,test在第3列
'匹配过程'
[root@oldboyedu ~]# echo -+=:/oldboy_=+-:test-/-=oldgirl | egrep -o "[-+=:/_]"
-
+
=
:
/
_
=
# 没加+号,每个字符单独匹配
[root@oldboyedu ~]# echo -+=:/oldboy_=+-:test-/-=oldgirl | egrep -o "[-+=:/_]+"
-+=:/
_=+-:
-/-=
# 加了+号,连续的符号视为一个整体

  • 如果上面的理解了,那么这个也难不倒你吧
  • 切两刀,这个IP地址在第②列

取列小结#

  • 默认连续空格和加了-F的,后面取的列数是不一样的
  • 上图是取inet这里一列
  • 如果是取IP地址呢?
  • 一个2,一个2,一个3([ /]+),不一样

总结来说,就是如果是默认的情况,开头即使有一些连续的字符什么的,他都给忽略了

3)⭐取行+取列#

我们刚才在用取行的时候,默认只用了**“条件”;而我们在取列的时候默认只用了”动作”,现在我们就中和**一下他们

📌 语法结构:

Terminal window
awk '找谁{干啥}' file
# 直接指定行数
awk '/找谁/{干啥}' file
# 利用正则模糊匹配

🌰 案例:输出文件大于3小于6的行的第一列和最后一列

Terminal window
[root@oldboyedu ~]# awk 'NR>3&&NR<6' passwd.txt
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
# 这里只取行
[root@oldboyedu ~]# awk -F':' 'NR>3&&NR<6{print $1,$NF}' passwd.txt
adm /sbin/nologin
lp /sbin/nologin
# 取行的同时 -F指定分隔符,打印指定列数

🌰 案例:找出包含root的行,输出最后一列内容

Terminal window
[root@oldboyedu ~]# awk -F':' '/root/{print $NF}' passwd.txt
/bin/bash
/sbin/nologin

🌰 案例:取出当前磁盘的使用率是多少

Terminal window
[root@oldboyedu ~]# df -h | awk 'NR==6'
/dev/mapper/klas-root 47G 3.5G 44G 8% /
[root@oldboyedu ~]# df -h | awk 'NR==6{print $(NF-1)}'
8%
# 取倒数第二列

或者

Terminal window
[root@oldboyedu ~]# df -h | awk '/\/$/'
/dev/mapper/klas-root 47G 3.5G 44G 8% /
# 匹配以/结尾的行,用撬棍把第二个/打回原形!
'这个思想很巧妙'
[root@oldboyedu ~]# df -h | awk '/\/$/{print $(NF-1)}'
8%
# 也是倒数第二列

📌 面试题:取出文件中的第5行的第3列

Terminal window
[root@oldboyedu ~]# awk 'NR==5{print $3}' file
'so easy 啦!'

⭐数字比较#

📌 语法格式:

Terminal window
awk '$3==0' file
awk '$3>5' file

如果某列是数字,可以做以下比较输出

== > >= < <= !=

🌰 案例:取出第3列等于0的行

Terminal window
[root@oldboyedu ~]# awk -F':' '$3==0' passwd.txt
root:x:0:0:root:/root:/bin/bash
# 得有这-F指定分隔符

🌰 案例:取出第三列大于5的行

Terminal window
[root@oldboyedu ~]# awk -F':' '$3>5' passwd.txt
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin

🌰 案例:取出第三列大于3并且小于6的行

Terminal window
[root@oldboyedu ~]# awk -F':' '$3>3&&$3<6' passwd.txt
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync

Terminal window
[root@oldboyedu ~]# awk -F':' '$3>3&&$3<6' passwd.txt | column -t
# column -t 对齐

💝妙用#

  • 很新颖!
  • 后面不打印列数,直接用” “打印想要输出的话

加行数#

很少用(每一行加一)

📌 类似于 wc -l统计行数但是你得了解END的使用

  • i初值为0,后面加的是1,相当于每行加1

BEGIN: 在读取文件之前做的动作 END:在读取文件之后做的动作

也就END用的多一点

这个案例后期,可以搭配各种条件使用

⭐加列数#

$行数(加上每一列的具体的值)

  • i的初值为0
  • 前面可以跟过滤条件 // 进行限制

字符串匹配#

⚠️ **注意:**用双引号将字符串包裹起来

输出第一列等于root的行

Terminal window
[root@oldboyedu ~]# awk -F':' '$1=="root"' passwd.txt
root:x:0:0:root:/root:/bin/bash

输出第一列不等于root的行

Terminal window
[root@oldboyedu ~]# awk -F':' '$1!="root"' passwd.txt
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

输出最后一列等于/sbin/halt的行

Terminal window
[root@oldboyedu ~]# awk -F':' '$NF=="/sbin/halt"' passwd.txt
halt:x:7:0:halt:/sbin:/sbin/halt

⭐~ (波浪线)#

📌 匹配第6列以v开头的行

Terminal window
[root@oldboyedu ~]# awk -F "[:/]+" '$6 ~ /^v/' passwd.txt
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

🌰 案例:第四列以0或者1开头的行

  • 没有$~ 就是对整个行进行正则匹配,而不是单独的某一列


02.三剑客习题#

Terminal window
[root@oldboyedu ~]# egrep -i 'oldboy' file
# egrep -i 忽略大小写

  • 下图的点为任意一个字符

  • 加上撬棍变成普通的点

sed命令实现:

  1. 反向引用

  • 因为贪心算法,匹配到最后一个:

egrep命令实现:## 难点在于写出用户名的表达式

取最后一行#

xargs查找/etc/下面所有文件中的一句话#

⚠️ 审题:所有文件,不是下面一层文件,所以find命令中没有 -maxdepth 1 这个限制

**场景:**电脑中病毒,每个文件中都有这一句

反引号$()都是取里面的命令并执行

Terminal window
[root@oldboyedu ~]# find /etc/ -type f | xargs grep 'linux'
# xargs grep 'linux'

删除空行#

典型工作流示例#

📌 分析网站访问日志:统计IP访问量并排序

Terminal window
[root@oldboyedu ~]# awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10
1428 192.168.1.23
1205 10.0.0.45
983 172.16.5.201
# ... (TOP 10 IPs)

统计每一个字符(单词)出现的次数,并取出次数最多的前10位#

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

三剑客-awk
https://www.kpyun.fun/posts/basics/core/core13/
作者
久棹
发布于
2025-08-10
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
久棹
只要胆子大,天天寒暑假!
公告
欢迎来到久棹的技术小站!本站专注 Linux 运维学习笔记分享,如有问题欢迎交流探讨 🎉
分类
标签
站点统计
文章
98
分类
11
标签
203
总字数
244,453
运行时长
0
最后活动
0 天前
站点信息
构建平台
Local
博客版本
Firefly v6.13.5
文章许可
CC BY-NC-SA 4.0

文章目录