一、sed 和变量联动是替换类操作的常见写法

原笔记用 IP 段替换做了一个非常典型的例子:

cat ip.txt
10.0.0.5
10.0.0.6
10.0.0.7
10.0.0.8
10.0.0.9

src=10.0.0
dst=172.16.1
sed "s#$src#$dst#g" ip.txt

这里有两个值得记住的点:

  • sed 里使用 Shell 变量时,要用双引号而不是单引号。
  • 分隔符不一定非要用 /,像 # 这种写法在处理路径和 IP 时更方便。

二、awk 最基础的能力是按列取值

原笔记给出的几个例子,几乎覆盖了日常最常见的列提取写法。

2.1 提取 /etc/passwd 指定行和列

awk -F: 'NR>=2 && NR<=9{print $1,$3}' /etc/passwd

这里:

  • -F: 指定冒号为分隔符
  • NR 表示当前行号
  • $1$3 表示第 1 列和第 3 列

2.2 条件匹配后取最后一列

awk -F: '$1=="root"{print $NF}' /etc/passwd

$NF 表示最后一列,是 awk 里非常高频的写法。

2.3 通过变量传值给 awk

name=root
awk -F: -vn=$name '$1==n{print $NF}' /etc/passwd

这说明 awk -v 不只是用来做计算,也是 Shell 和 awk 传参的通用方式。

三、awk 也能处理判断和循环

3.1 判断磁盘是否超过阈值

原笔记给出的示例是:

df -h | awk -F"[ %]+" '$NF=="/" && $(NF-1)>=80 {print "磁盘空间不足"}'

这个例子很适合理解 awk 里的几个基础点:

  • 分隔符可以是正则
  • $NF 是最后一列
  • $(NF-1) 是倒数第二列
  • 条件满足时可以直接 print

3.2 awk 里的循环

awk 'BEGIN{for(i=1;i<=100;i++) sum=sum+i; print sum}'

也就是说,awk 不只是“按列打印”,它本身就具备轻量级脚本语言的特征。

四、awk 数组和 Shell 数组有什么不同

原笔记特别强调:

  • Shell 数组默认以下标数字为主
  • awk 数组是关联数组,下标可以是字符串

这就是为什么做日志统计、去重计数、分类汇总时,awk 往往比纯 Shell 更合适。

4.1 创建和读取 awk 数组

awk 'BEGIN{array[0]="lidao996";array["lidao"]=996;array[110]="sos";print array[0]}'

4.2 遍历 awk 数组

awk 'BEGIN{
    array[0]="lidao996"
    array["lidao"]=996
    array[110]="sos"
    for (n in array)
        print n, array[n]
}'

这里的 for (n in array)awk 数组统计最核心的语法。

五、案例:统计每个域名出现了多少次

原笔记给出的 URL 统计案例,非常适合理解 awk 数组的优势:

awk -F'/+' '{url[$2]++} END{for(name in url) print name, url[name]}' /server/files/url.txt

思路其实很简单:

1、用 -F'/+' 把 URL 分隔开。 2、取域名所在的 $2 作为数组下标。 3、每读到一次就加 1。 4、最后统一输出。

这种模式几乎可以直接迁移到:

  • 域名访问次数统计
  • 用户行为次数统计
  • 错误码次数统计
  • IP 访问次数统计

六、案例:统计访问日志中每个 IP 的总流量

原笔记还给出了一个“去重求和”的例子:

awk '{liu[$1]=liu[$1]+$10} END{for(ip in liu) print ip, liu[ip]}' /var/log/nginx/access.log-20240104 | sort -rnk2 | head

这个例子说明:

  • $1 可以作为 IP 地址键
  • $10 可以作为流量值
  • 每行都把流量加到对应 IP 上
  • 最后再排序取 Top N

相比先 sort | uniq 再做其他处理,awk 这种“边读边统计”的方式通常更直接。

七、awk 和 Shell 语法该怎么对照理解

原笔记最后给了一组对照关系,非常适合复习:

  • Shell 的 if ... then ... fi,对应 awk 里的 if (...) { ... }
  • Shell 的 for((i=1;i<=10;i++)),对应 awkfor(i=1;i<=10;i++)
  • Shell 的通用列表循环 for n in list,对应 awk 的数组循环 for (n in array)

一旦把这些对应关系建立起来,学习三剑客时就不会觉得它和 Shell 是两套完全割裂的东西。

八、这一篇内容为什么放在最后

因为 Shell 自动化真正进阶的节点,不是多会几个系统命令,而是开始能把日志、配置、文本结果快速提炼成结构化数据,再根据结果做判断和处理。

sed 负责替换,awk 负责提取、判断和统计,Shell 负责把这些能力组织成完整流程。三者组合起来,才是自动化运维里最常见、也最实用的一套文本处理工具链。