一、sed 命令详解
1.1 sed 命令概述
sed(Stream Editor,流编辑器)是 CentOS 7 中用于对文本进行流式处理的强大工具。它逐行读取输入文本(文件或标准输入),根据预设的编辑命令对每行内容进行处理,然后输出处理结果。sed 常用于文本替换、删除、插入、修改等操作,在脚本编写和系统管理等批量文本处理场景中应用广泛。
1.2 sed 命令语法结构
基本语法为:
TypeScript
取消自动换行复制
sed [选项] '编辑命令' [文件名]
- 选项:用于调整 sed 的行为。
- 编辑命令:指定对文本的具体操作,如替换、删除、插入等。
- 文件名:指定要处理的文件,若省略文件名,sed 将从标准输入读取数据。
1.3 常用选项详解
|-----|----------------------|---------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------|
| 选项 | 全称 | 功能描述 | 示例 |
| -n | --quiet, --silent | 默认情况下,sed 会输出处理后的每一行;使用-n选项则仅输出经过特定命令处理且被显示的行 | sed -n '2p' file.txt:只输出文件中第 2 行的内容 |
| -e | --expression=script | 允许在一行中指定多个编辑命令 ,可多次使用 -e 追加命令 | sed -e's/abc/def/' -e '3d' file.txt:先将文件中的 "abc" 替换为 "def",再删除第 3 行 |
| -i | --in-place=SUFFIX | 直接修改原文件,而不是输出到标准输出。使用时需谨慎,建议提前备份文件;若指定SUFFIX,则会在修改前为原文件创建备份(备份文件名为原文件名加SUFFIX) | sed -i '.bak' s/old/new/g file.txt:将文件file.txt中的 "old" 替换为 "new",并创建名为file.txt.bak的备份文件 |
| -f | --file=script-file | 从指定的脚本文件中读取编辑命令 | 若有脚本文件sed_script.sed,内容为s/hello/world/,则执行sed -f sed_script.sed file.txt,将file.txt中的 "hello" 替换为 "world" |
| -r | --regexp-extended | 使用扩展正则表达式,部分元字符无需转义,简化复杂正则的书写 | sed -r's/([0-9]+)/[\1]/' file.txt:将文件中连续的数字字符串加上中括号,若使用普通正则,()需转义为\(\) |
| -s | --separate | 当处理多个文件时,将每个文件视为独立输入,不将多个文件内容连接处理 | 执行sed -s's/start/end/' file1.txt file2.txt,会分别对file1.txt和file2.txt进行替换,而不是将两个文件内容合并后处理 |
1.4 常用编辑命令及示例
1.4.1 替换命令(s)
功能:用于替换文本中的字符串,是 sed 最常用的命令之一。
语法:s/原字符串/新字符串/[g],其中g表示全局替换(若不使用g,则只替换每行中第一个匹配的字符串)。
示例:
- 将文件test.txt中所有的 "apple" 替换为 "banana":
TypeScript
取消自动换行复制
sed's/apple/banana/g' test.txt
- 仅替换每行中第一个 "hello" 为 "hi":
TypeScript
取消自动换行复制
sed's/hello/hi/' test.txt
- 按指定分隔符替换,如将/etc/passwd文件中以冒号分隔的第三个字段(用户 ID)为 1001:
TypeScript
取消自动换行复制
sed's/:/1001:2/' /etc/passwd
- 使用其他分隔符替换,避免与替换内容冲突,如将 "/home/user/doc/file.txt" 中的 "/" 替换为 "_":
TypeScript
取消自动换行复制
sed's|/|_|g' /home/user/doc/file.txt
1.4.2 删除命令(d)
功能:删除指定的行。
语法:行号d 或 地址范围d,其中行号可以是具体的数字,地址范围可以用逗号分隔起始行号和结束行号。
示例:
- 删除文件test.txt的第 3 行:
TypeScript
取消自动换行复制
sed '3d' test.txt
- 删除文件中第 2 行到第 5 行的内容:
TypeScript
取消自动换行复制
sed '2,5d' test.txt
- 删除包含 "error" 的行:
TypeScript
取消自动换行复制
sed '/error/d' log.txt
- 删除以 "#" 开头的注释行:
TypeScript
取消自动换行复制
sed '/^#/d' config.ini
1.4.3 插入命令(i)和追加命令(a)
功能:i用于在指定行前插入内容,a用于在指定行后追加内容。
语法:行号i 或 行号a,然后在新行输入要插入或追加的内容,以Ctrl + D结束输入;也可直接在命令后添加内容,如行号i 内容。
示例:
- 在文件test.txt的第 2 行前插入 "new line":
TypeScript
取消自动换行复制
sed '2i new line' test.txt
- 在文件末尾追加一行内容:
TypeScript
取消自动换行复制
sed '$a This is the last line' test.txt
- 在包含 "target" 的行前插入新行:
TypeScript
取消自动换行复制
sed '/target/i insert line before target' file.txt
1.4.4 修改命令(c)
功能:将指定的行替换为新的内容。
语法:行号c,然后输入新内容,以Ctrl + D结束;也可直接在命令后添加新内容,如行号c 新内容。
示例:
- 将文件test.txt的第 3 行修改为 "modified line":
TypeScript
取消自动换行复制
sed '3c modified line' test.txt
- 将包含 "old_content" 的行修改为 "new_content":
TypeScript
取消自动换行复制
sed '/old_content/c new_content' file.txt
1.5 sed 高级应用场景
1.5.1 批量修改文件内容
在项目开发中,可能需要批量修改多个文件中的某个字符串。例如,将项目中所有.html文件里的 "old_domain.com" 替换为 "new_domain.com":
TypeScript
取消自动换行复制
sed -i's/old_domain.com/new_domain.com/g' *.html
注意,使用-i选项时务必先备份文件,防止误操作导致数据丢失。若要同时备份文件,可使用sed -i.bak's/old_domain.com/new_domain.com/g' *.html,会生成.bak后缀的备份文件。
1.5.2 结合正则表达式处理复杂文本
当处理包含特殊字符或复杂格式的文本时,可借助正则表达式。比如,从日志文件中提取所有以 "ERROR" 开头的行,并将错误代码(数字部分)替换为 "XXXX":
TypeScript
取消自动换行复制
sed -n '/^ERROR/s/ERROR [0-9]*/ERROR XXXX/p' error.log
这里-n选项配合p命令(打印匹配行),只输出经过替换后的错误行。若要提取 IP 地址(格式为xxx.xxx.xxx.xxx),可使用:
TypeScript
取消自动换行复制
sed -n's/.*\([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+\).*/\1/p' log.txt
此命令通过正则表达式提取每行中的 IP 地址并输出。
二、awk 命令详解
2.1 awk 命令概述
awk是一种强大的文本处理编程语言,它以字段为单位对文本进行处理,能够轻松实现数据提取、格式化输出、统计计算等功能。awk 的工作模式是逐行读取输入文本,根据指定的规则将每行文本拆分成字段,然后对字段进行操作和处理。它在数据分析、日志处理、报表生成等场景中发挥着重要作用。
2.2 awk 命令语法结构
基本语法为:
TypeScript
取消自动换行复制
awk [选项] '模式 {动作}' [文件名]
- 选项:常用选项用于设置字段分隔符等参数。
- 模式:用于筛选符合条件的行,模式可以是正则表达式、关系表达式或行号范围等。如果省略模式,默认对所有行执行动作。
- 动作:是 awk 执行的具体操作,包括打印字段、计算、赋值等,动作由一系列语句组成,用大括号{}括起来。
- 文件名:指定要处理的文件,若省略文件名,awk 将从标准输入读取数据。
2.3 常用选项详解
|-----|-----------------------|-------------------------------|----------------------------------------------------------------------------------------------|
| 选项 | 全称 | 功能描述 | 示例 |
| -F | --field-separator=fs | 指定字段分隔符,默认是空格或制表符 ,fs为自定义分隔符 | awk -F: '{print 1, 3}' /etc/passwd:以冒号为分隔符,打印/etc/passwd文件中每行的用户名(第 1 个字段)和用户 ID(第 3 个字段) |
| -v | --assign=var=value | 定义或赋值变量,在 awk 脚本中使用 | awk -v num=10 '{if (1 \> num) print 1}' file.txt:定义变量num为 10,输出文件中第一个字段大于 10 的行的第一个字段 |
| -f | --file=script-file | 从指定的脚本文件中读取 awk 脚本 | 若有脚本文件awk_script.awk,内容为{print $0},则执行awk -f awk_script.awk file.txt,输出file.txt的所有行 |
| -F | --lint | 对 awk 脚本进行语法检查,输出可能存在的问题 | awk --lint'script.awk':检查script.awk脚本的语法错误 |
| -W | --help, --usage | 显示 awk 的帮助信息和使用方法 | awk --help:查看 awk 命令的详细帮助文档 |
2.4 常用内置变量及示例
awk 提供了多个内置变量,方便对文本字段进行操作:
- $0:表示整行文本。
-
1,
2,...:表示每行的第 1 个字段、第 2 个字段,以此类推。
- NF:表示当前行的字段数量。
- NR:表示当前处理的行号。
- FS:字段分隔符(默认是空格或制表符),可通过-F选项或在脚本中设置。
- OFS:输出字段分隔符,用于设置输出时字段之间的分隔符。
示例:
- 以冒号为分隔符,打印/etc/passwd文件中每行的用户名(第 1 个字段)和用户 ID(第 3 个字段):
TypeScript
取消自动换行复制
awk -F: '{print 1, 3}' /etc/passwd
- 统计文件的行数:
TypeScript
取消自动换行复制
awk 'END {print NR}' file.txt
这里END是 awk 的特殊模式,表示处理完所有行后执行动作。
- 设置输出字段分隔符为逗号,打印文件中每行的前两个字段:
TypeScript
取消自动换行复制
awk -F' ' 'BEGIN {OFS=","} {print 1, 2}' file.txt
BEGIN是 awk 的另一个特殊模式,在处理文件内容前执行动作,这里用于设置输出分隔符。
2.5 典型操作及示例
2.5.1 数据提取
从日志文件access.log中提取所有访问 IP 地址(假设 IP 地址在每行的第 1 个字段):
TypeScript
取消自动换行复制
awk '{print $1}' access.log
若日志格式为IP地址 - 时间 - 访问路径,以空格为分隔符,可使用:
TypeScript
取消自动换行复制
awk -F' - ' '{print $1}' access.log
- 提取包含特定字符串的行的某个字段,如从日志中提取包含 "GET" 请求的行的 URL(假设 URL 在第 4 个字段):
TypeScript
取消自动换行复制
awk '/GET/ {print $4}' access.log
2.5.2 数据统计
计算文件中某列数据的总和。例如,有一个记录销售额的文件sales.txt,格式为产品名称 销售额,计算总销售额:
TypeScript
取消自动换行复制
awk '{sum += $2} END {print sum}' sales.txt
这里通过sum += $2将每行的销售额累加到sum变量中,处理完所有行后,在END模式下输出总和。
- 统计每个产品的销售数量,文件orders.txt格式为产品ID 销售数量:
TypeScript
取消自动换行复制
awk '{count[1\] += 2} END {for (id in count) {print id, count[id]}}' orders.txt
使用数组count以产品 ID 为下标统计销售数量,最后输出每个产品 ID 及其总销售数量。
2.5.3 数据格式化输出
将/etc/passwd文件中的用户名和用户 ID 按照指定格式输出:
TypeScript
取消自动换行复制
awk -F: '{printf "用户名: %s, 用户ID: %s\n", 1, 3}' /etc/passwd
printf函数用于格式化输出,与 C 语言中的printf函数类似,可指定输出格式。
- 输出一个简单的表格,文件students.txt格式为姓名 年龄 成绩:
TypeScript
取消自动换行复制
awk -F' ' 'BEGIN {printf "%-10s %-5s %-5s\n", "姓名", "年龄", "成绩"} {printf "%-10s %-5d %-5d\n", 1, 2, $3}' students.txt
BEGIN模式先输出表头,然后逐行按照指定格式输出学生信息,%-10s表示左对齐,宽度为 10 个字符的字符串格式。
2.6 awk 高级应用场景
2.6.1 复杂条件筛选
从日志文件中筛选出访问次数大于 100 的 IP 地址及其访问次数。假设日志文件access.log格式为IP地址 访问次数:
TypeScript
取消自动换行复制
awk '{count[1\] += 2} END {for (ip in count) {if (count[ip] > 100) {print ip, count[ip]}}}' access.log
这里使用数组count统计每个 IP 地址的总访问次数,在END模式下遍历数组,筛选出符合条件的 IP 地址并输出。
- 筛选出成绩大于 80 分且年龄小于 25 岁的学生信息,文件students.txt格式为姓名 年龄 成绩:
TypeScript
取消自动换行复制
awk -F' ' '{if (2 \< 25 \&\& 3 > 80) print $0}' students.txt
2.6.2 多文件处理
同时处理多个文件,并对文件中的数据进行合并统计。例如,有多个销售数据文件sales1.txt、sales2.txt等,格式均为产品名称 销售额,计算所有文件中产品的总销售额:
TypeScript
取消自动换行复制
awk '{sum[1\] += 2} END {for (product in sum) {print product, sum[product]}}' sales*.txt
通过数组sum按产品名称统计销售额,最后输出每个产品的总销售额。
- 合并多个文件的特定字段,文件file1.txt和file2.txt格式均为字段1 字段2,将两个文件的字段 1 合并输出:
TypeScript
取消自动换行复制
awk 'FNR==NR {a[NR]=1; next} {print a\[FNR\], 1}' file1.txt file2.txt
FNR表示当前文件的行号,NR表示总的行号,先读取file1.txt将字段 1 存入数组a,再读取file2.txt并结合数组a输出合并结果。
三、sed 与 awk 的对比与结合使用
3.1 功能对比
|------|----------------------------------|---------------------------|
| 工具 | 功能特点 | 适用场景 |
| sed | 侧重于文本的编辑和修改,如字符串替换、行的增删改等操作 | 文本格式转换、批量替换字符串、删除或修改特定行等 |
| awk | 擅长数据的提取、分析和统计,能够以字段为单位对文本进行复杂处理 | 数据分析、日志处理、报表生成、数据计算等 |