sed修改文件简介

sed修改文件简介

前言

在日常的 Linux 运维和开发工作中,我们经常需要对文本文件进行批量编辑、替换、删除等操作。虽然可以用 Vim 手动编辑,但当面对大文件或需要自动化处理时,sed 就是你的最佳选择。

sedStream Editor(流编辑器)的缩写,它可以在不打开文件的情况下,对文本进行高效的编辑处理。本文将带你从零开始,掌握 sed 的核心用法。


一、sed 是什么?

sed 是一个非交互式文本编辑器,它按照预设的规则逐行处理文本,适用于:

  • 批量替换文件中的字符串
  • 删除或提取特定行
  • 插入、追加、修改文本内容
  • 自动化脚本中的文本处理

基本语法

sed [选项] '命令' 文件名

常用选项

选项说明
-i直接修改原文件(危险操作,建议先备份)
-e执行多个 sed 命令
-n静默模式,只打印被处理的行
-r-E使用扩展正则表达式

二、核心概念:地址定位

sed 的核心是 “找位置 → 做操作”。你需要告诉 sed 要处理哪些行(地址),然后执行什么操作(命令)。

地址定位方式

# 1. 不指定地址:处理所有行
sed 'd' file.txt        # 删除所有行

# 2. 指定行号
sed '3d' file.txt       # 删除第3行
sed '5,10d' file.txt    # 删除第5-10行

# 3. 使用正则匹配
sed '/error/d' file.txt # 删除包含error的行

# 4. 从匹配行到文件末尾
sed '/start/,$d' file.txt

# 5. 使用行号与正则混合
sed '5,/error/d' file.txt # 从第5行删到匹配error的行

取反操作 !

# 不删除第3行(即保留第3行,删除其他所有行)
sed '3!d' file.txt

# 删除不包含error的行
sed '/error/!d' file.txt

三、增删改查:sed 四大核心操作

1. 删除(d)

# 删除空行
sed '/^$/d' file.txt

# 删除注释行(以#开头)
sed '/^#/d' file.txt

# 删除第2行到最后一行
sed '2,$d' file.txt

# 删除最后一行
sed '$d' file.txt

# 删除包含特定字符串的行
sed '/delete_this/d' file.txt

# 删除奇数行
sed '1~2d' file.txt  # 1,3,5...行

2. 替换(s///)

这是 sed 最常用的功能。

# 基本替换:将第一个apple替换为orange
sed 's/apple/orange/' file.txt

# 全局替换(所有匹配)
sed 's/apple/orange/g' file.txt

# 只替换第2个匹配
sed 's/apple/orange/2' file.txt

# 替换第3行到第5行的内容
sed '3,5 s/apple/orange/g' file.txt

# 使用其他分隔符(当路径包含/时)
sed 's|/usr/bin|/usr/local/bin|g' file.txt
sed 's#/usr/bin#/usr/local/bin#g' file.txt

# 忽略大小写
sed 's/apple/orange/gi' file.txt

# 替换并打印修改的行
sed -n 's/apple/orange/gp' file.txt

高级替换:使用分组

# 交换前两个单词
echo "John Doe" | sed 's/\([^ ]*\) \(.*\)/\2 \1/'
# 输出: Doe John

# 提取IP地址
echo "IP: 192.168.1.1" | sed 's/.*: \([0-9.]*\)/\1/'
# 输出: 192.168.1.1

# 添加HTML标签
sed 's/.*/<p>&<\/p>/' file.txt  # &代表匹配的整个内容

3. 打印(p)与静默模式(-n)

# 打印第5行
sed -n '5p' file.txt

# 打印匹配的行
sed -n '/error/p' file.txt

# 打印第10行到第20行
sed -n '10,20p' file.txt

# 打印行号
sed -n '=; p' file.txt  # 先打印行号,再打印内容

# 打印匹配行的行号和内容
sed -n '/error/{=;p}' file.txt

4. 插入、追加、修改

# i: 在匹配行之前插入
sed '/pattern/i\这是插入的新行' file.txt

# a: 在匹配行之后追加
sed '/pattern/a\这是追加的新行' file.txt

# c: 替换整行
sed '/pattern/c\这行被替换了' file.txt

# 在第3行前插入
sed '3i\插入的内容' file.txt

# 在第3行后追加
sed '3a\追加的内容' file.txt

四、实战案例

案例1:批量修改配置文件

# 将nginx配置中的端口从8080改为80
sed -i 's/listen 8080;/listen 80;/g' /etc/nginx/sites-available/default

# 注释掉包含特定配置的行
sed -i '/^sendfile on;/s/^/#/' /etc/nginx/nginx.conf

案例2:清理日志文件

# 删除DEBUG级别的日志
sed -i '/DEBUG/d' app.log

# 只保留最近7天的日志(假设日志格式包含日期2025-01-01)
sed -n '/2025-05-1[6-9]/,$p' app.log

案例3:CSV文件处理

# 替换CSV中的空字段为NULL
sed -i 's/,,/,NULL,/g' data.csv
sed -i 's/,$/,NULL/' data.csv

# 删除CSV表头
sed -i '1d' data.csv

案例4:代码批量修改

# 将所有Python print改为logging
sed -i 's/print(/logging.info(/g' *.py

# 添加版权信息到文件开头
sed -i '1i\# Copyright 2025 My Company' *.py

案例5:从HTML中提取内容

# 提取所有title标签内容
sed -n 's/.*<title>\(.*\)<\/title>.*/\1/p' index.html

# 删除所有HTML标签
sed 's/<[^>]*>//g' page.html

案例6:给配置文件每行添加引号

# 每行添加双引号
sed 's/^/"/; s/$/"/' config.txt

# 输出示例:
# "line1"
# "line2"

案例7:生成SQL插入语句

# 将数据文件转换为SQL
sed "s/^/INSERT INTO users VALUES ('/; s/$/');/" data.txt

# data.txt内容:
# john,25
# mary,30

# 输出:
# INSERT INTO users VALUES ('john,25');
# INSERT INTO users VALUES ('mary,30');

案例8:Markdown转HTML

# 给每行添加HTML段落标签
sed 's/^/<p>/; s/$/<\/p>/' article.txt

案例9:日志添加时间戳

# 在每行行首添加当前时间
sed "s/^/$(date '+%Y-%m-%d %H:%M:%S') /" app.log

案例10:CSV转JSON(简化版)

# 给CSV每行添加JSON格式
sed 's/^/{"data": "/; s/$/"}/' data.csv

五、多命令组合

使用 -e 选项

# 删除空行和注释行
sed -e '/^$/d' -e '/^#/d' file.txt

# 等价于
sed '/^$/d; /^#/d' file.txt

使用分号 ;

# 替换多个字符串
sed 's/cat/dog/g; s/white/black/g' file.txt

# 先替换再删除空行
sed 's/foo/bar/g; /^$/d' file.txt

使用花括号 {} 对同一地址执行多个命令

# 对第10-20行执行多个操作
sed '10,20{
    s/foo/bar/g
    s/abc/xyz/g
    /^$/d
}' file.txt

六、sed 脚本文件

当命令复杂时,可以写成脚本文件。

bash

# 创建脚本 script.sed
cat > script.sed << 'EOF'
#!/usr/bin/sed -f
# 删除空行
/^$/d
# 替换字符串
s/old/new/g
# 在文件末尾添加结束标记
$a\# End of file
EOF

# 执行脚本
sed -f script.sed input.txt > output.txt

七、常见陷阱与注意事项

1. -i 选项的风险

# 危险:直接修改原文件且无法恢复
sed -i 's/old/new/g' important.conf

# 安全做法:先备份
sed -i.bak 's/old/new/g' important.conf

# 预览修改(不实际修改)
sed 's/old/new/g' important.conf | less

2. 特殊字符需要转义

需要转义的字符:. * [ ^ $ \ / ( )

# 错误:. 被解释为正则
echo "192.168.1.1" | sed 's/192.168.1.1/IP/g'  # 不工作

# 正确:转义点号
echo "192.168.1.1" | sed 's/192\.168\.1\.1/IP/g'

# 或者使用其他分隔符避免转义/
echo "/usr/local/bin" | sed 's|/usr/local/bin|/opt/bin|'

八、sed 与其他命令的配合

与 grep 配合

# 先过滤再编辑
grep 'ERROR' app.log | sed 's/ERROR/WARNING/g'

# 等价于
sed -n '/ERROR/s/ERROR/WARNING/p' app.log

与 awk 配合

# awk处理列,sed处理格式
awk '{print $1, $3}' data.txt | sed 's/^/Record: /'

与管道组合

# 实时监控日志并脱敏
tail -f app.log | sed 's/[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}/DATE/g'

# 格式化命令输出
ps aux | sed -n '2,$p' | sed 's/\([^ ]*\).*/\1/'  # 提取第一列

九、快速参考卡

操作命令示例
删除空行sed '/^$/d'
删除第5行sed '5d'
删除5-10行sed '5,10d'
删除包含pattern的行sed '/pattern/d'
全局替换sed 's/old/new/g'
只替换第2个匹配sed 's/old/new/2'
打印第5行sed -n '5p'
打印匹配行sed -n '/pattern/p'
在第3行前插入sed '3i\新行'
在第3行后追加sed '3a\新行'
替换整行sed '/pattern/c\新内容'
多重命令sed -e 'cmd1' -e 'cmd2'

十、进阶学习资源

  1. 正则表达式:sed 的灵魂,建议深入学习
  2. sed one-liners:网上有很多经典的单行脚本
  3. info sed:完整的 sed 官方文档

结语

sed 是每个 Linux 用户都应该掌握的工具。虽然它的语法看起来有些晦涩,但核心就是 “找位置,做操作”。建议你:

  1. 先在测试文件上练习
  2. 多用 -np 预览结果
  3. 重要操作前先用 -i.bak 备份

掌握 sed 后,你会发现文本处理效率提升 10 倍以上。动手试试吧!

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注