首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >十三、Linux Shell脚本:文本处理三剑客之 sed 与 awk

十三、Linux Shell脚本:文本处理三剑客之 sed 与 awk

作者头像
IvanCodes
发布2025-09-28 11:05:27
发布2025-09-28 11:05:27
14000
代码可运行
举报
运行总次数:0
代码可运行

在掌握grep和正则表达式之后,我们接着学习Linux命令行文本处理的另外两大核心工具:sed 和 awk 。grep 擅长查找,而 sed 擅长编辑,awk 则擅长格式化报告和复杂的数据处理。

一、流编辑器 sed

sed 是一个非交互式的流编辑器。它逐行读取文本,根据预设的规则对每行进行处理,并将结果输出到标准输出。默认不修改原始文件。

基本语法: sed [选项] '地址 命令' 文件名

  • 地址: 指定要操作的行。可以是行号 (如 3)、范围 (如 2,5) 或正则表达式 (如 /pattern/)。若省略,则应用于所有行。

常用命令:

1. d (delete) - 删除行
代码语言:javascript
代码运行次数:0
运行
复制
# 删除文件的第3行
sed '3d' /etc/passwd

# 删除文件第2到第5行
sed '2,5d' /etc/passwd

# 删除所有包含 "nologin" 字符串的行
sed '/nologin/d' /etc/passwd
2. p (print) - 打印行

p 命令通常与 -n 选项配合使用。-n 会禁止 sed 的默认输出,从而只打印被 p 命令明确指定的行。

代码语言:javascript
代码运行次数:0
运行
复制
# 只打印文件的第3行
sed -n '3p' /etc/passwd

# 只打印包含 "root" 的行 (效果类似 grep)
sed -n '/root/p' /etc/passwd
3. s (substitute) - 替换

这是 sed 最强大的命令。 语法: 's/pattern/replacement/flags'

pattern: 要匹配的正则表达式。 replacement: 要替换成的字符串。& 符号在replacement中代表被匹配到的整个内容。 flags: g: 全局替换行内的所有匹配。 i: 忽略大小写。 数字 (如 2): 只替换每行中第 N 次出现的匹配。

代码示例:

代码语言:javascript
代码运行次数:0
运行
复制
# 将每行第一个 "root" 替换为 "admin"
sed 's/root/admin/' /etc/passwd

# 将所有 "nologin" 替换为 "disabled"
sed 's/nologin/disabled/g' /etc/passwd

# 给所有数字加上方括号
echo "line 123 has number 456" | sed 's/[0-9][0-9]*/[&]/g'

# 使用 -i 选项直接修改文件 (危险操作,建议先备份)
sed -i.bak 's/old_text/new_text/g' /path/to/your/file
# (-i.bak 会创建一个 .bak 后缀的备份文件)

二、报告生成器 awk

awk 是一个强大的文本处理语言,它逐行读取输入,并将每行按分隔符切分成字段,极度擅长处理列式数据和生成报告。

基本语法: awk '[选项] 'pattern { action }' 文件名

核心概念:

Record: 默认情况下,每行是一个记录。 Field: 每个记录被分隔符切分成的部分。通过 1, 2, 3 … 引用,0 代表整行。 FS: 输入字段的分隔符。 NR: 当前记录的行号。 NF: 当前记录的字段数量。

Pattern (模式): 决定是否对当前行执行 action。可以是正则表达式、条件表达式或特殊的 BEGIN / ENDAction (动作): 花括号 {} 中包含的一系列命令。

常用命令与功能:

1. 打印指定字段
代码语言:javascript
代码运行次数:0
运行
复制
# 打印 /etc/passwd 文件的第一列 (用户名)
awk -F: '{print $1}' /etc/passwd

# 打印 /etc/passwd 文件的第一列和最后一列
awk -F: '{print "User:", $1, "| Shell:", $NF}' /etc/passwd
  • -F:: 指定字段分隔符为冒号。
2. 使用模式进行过滤
代码语言:javascript
代码运行次数:0
运行
复制
# 只打印包含 "root" 的行
awk '/root/' /etc/passwd

# 只打印第三个字段(UID)小于10的行
awk -F: '$3 < 10 {print $0}' /etc/passwd

# 只打印奇数行
awk 'NR % 2 == 1' /etc/passwd
3. 使用 BEGINEND 模式
  • BEGIN { ... }: 在处理任何行之前执行,用于初始化或打印表头。
  • END { ... }: 在处理完所有行之后执行,用于计算汇总和打印结果。

代码示例:

代码语言:javascript
代码运行次数:0
运行
复制
# 统计 /etc/passwd 文件的用户总数
awk 'END {print "Total users:", NR}' /etc/passwd

# 打印磁盘使用情况报告,并添加表头
df -h | awk 'BEGIN {printf "%-30s %-10s %-10s\n", "Filesystem", "Size", "Used%"} NR>1 {printf "%-30s %-10s %-10s\n", $1, $2, $5}'

三、总结

本次我们深入学习了Linux文本处理三剑客中的sedawksed 作为流编辑器,其核心优势在于对文本行进行删除、打印和替换操作。而awk 则更像一个微型编程语言,它按字段处理数据,擅长从结构化文本中提取信息、计算、生成格式化的报告。在实际工作中,经常将 grep, sed, awk 通过管道组合使用,以完成复杂的文本处理任务。


练习题

背景文件 server.log 内容:

代码语言:javascript
代码运行次数:0
运行
复制
2024-08-08 10:00:15 INFO: User 'alice' logged in from 192.168.1.10.
2024-08-08 10:02:30 DEBUG: System check initiated.
2024-08-08 10:03:05 WARNING: Disk space is running low on /dev/sda1.
2024-08-08 10:05:45 INFO: User 'bob' accessed resource 'file.txt'.
2024-08-08 10:06:22 ERROR: Failed to connect to database 'prod_db'.

题目:

  1. sed删除: 使用 sed 命令,删除 server.log 中所有 DEBUG 级别的日志行。
  2. sed打印: 使用 sed 命令,只打印出 server.log 文件的第 2 到第 4 行。
  3. sed替换: 使用 sed 命令,将 server.log 中所有出现的 “User” (首字母大写) 替换为 “Client”。
  4. awk打印字段: server.log 的日志级别是第3个字段 (以空格为分隔符)。请使用 awk 命令,打印出所有日志行的日期 (第1个字段) 和日志级别。
  5. awk模式匹配: 使用 awk 命令,只打印 server.log 中包含 ERROR 信息的完整日志行。
  6. awk内置变量: 使用 awk 命令,打印 server.log 中字段数超过8个的所有行。
  7. awk BEGIN/END: 使用 awk 命令,统计 server.logINFO, WARNING, ERROR 日志各自出现的次数。
  8. sed综合: 写一条 sed 命令,将 server.log 中所有 INFO 日志行的行首添加 [INFO_LOG] 前缀。
  9. awk与sed组合: 使用管道,先用 sed 过滤出 server.log 中所有 INFO 级别的日志,然后用 awk 提取并打印出用户名 (假设用户名总是在单引号 ' ' 中)。
  10. sed替换指定出现次数: 写一条 sed 命令,只替换 server.log 中每行第二次出现的冒号 : 为分号 ;

答案与解析

  1. sed删除:
代码语言:javascript
代码运行次数:0
运行
复制
sed '/DEBUG:/d' server.log
  • 解析: '/DEBUG:/d' 使用正则表达式 /DEBUG:/ 作为地址,匹配所有包含 “DEBUG:” 的行,并用 d 命令删除它们。
  1. sed打印:
代码语言:javascript
代码运行次数:0
运行
复制
sed -n '2,4p' server.log
  • 解析: -n 禁止默认输出。2,4 是行号范围地址,p 命令只打印这个范围内的行。
  1. sed替换:
代码语言:javascript
代码运行次数:0
运行
复制
sed 's/User/Client/g' server.log
  • 解析: s/User/Client/g 将所有出现的 “User” 替换为 “Client”。g 标志确保全局替换。
  1. awk打印字段:
代码语言:javascript
代码运行次数:0
运行
复制
awk '{print $1, $3}' server.log
  • 解析: awk 默认以空格或制表符为分隔符。1 是日期,3 是日志级别。{print 1, 3} 打印这两个字段。
  1. awk模式匹配:
代码语言:javascript
代码运行次数:0
运行
复制
awk '/ERROR/' server.log
  • 解析: awk 的模式部分如果没有对应的 { action },则默认动作就是 {print $0} (打印整行)。/ERROR/ 匹配包含 “ERROR” 的行。
  1. awk内置变量:
代码语言:javascript
代码运行次数:0
运行
复制
awk 'NF > 8' server.log
  • 解析: NF > 8 是一个条件模式,NF 是当前行的字段数。只有当字段数大于8时,条件为真,执行默认的打印整行动作。
  1. awk BEGIN/END:
代码语言:javascript
代码运行次数:0
运行
复制
awk '/INFO/ {info_count++} /WARNING/ {warn_count++} /ERROR/ {error_count++} END {print "INFO:", info_count, "WARNING:", warn_count, "ERROR:", error_count}' server.log
  • 解析: awk 可以有多个 pattern { action } 组合。它会遍历每一行,匹配对应的模式并执行动作 (累加计数器)。END 块在最后打印所有计数器的汇总结果。
  1. sed综合:
代码语言:javascript
代码运行次数:0
运行
复制
sed '/INFO/s/^/[INFO_LOG] /' server.log
  • 解析: /INFO/ 是地址,表示只对包含 “INFO” 的行执行命令。s/^/[INFO_LOG] / 是替换命令,^ 匹配行首,将其替换为指定的前缀。
  1. awk与sed组合:
代码语言:javascript
代码运行次数:0
运行
复制
sed -n '/INFO/p' server.log | awk -F"'" '{print $2}'

解析:

  • sed -n '/INFO/p' server.log: 首先过滤出所有INFO日志行。
  • |: 管道将结果传给awk
  • awk -F"'" '{print
  1. sed替换指定出现次数:
代码语言:javascript
代码运行次数:0
运行
复制
sed 's/:/;/2' server.log
  • 解析: s/pattern/replacement/flags 中的 flags 可以是一个数字。2 表示只替换每行中第二次出现的匹配项。

日期:2025年8月12日 专栏:Linux教程

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-09-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、流编辑器 sed
    • 1. d (delete) - 删除行
    • 2. p (print) - 打印行
    • 3. s (substitute) - 替换
  • 二、报告生成器 awk
    • 1. 打印指定字段
    • 2. 使用模式进行过滤
    • 3. 使用 BEGIN 和 END 模式
  • 三、总结
  • 练习题
  • 答案与解析
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档