Linux Shell 之 sed

Lear 2025-07-14 10:00:00
Categories: Tags:

Linux Shell 之 sed

sed 是一种流编辑器(Stream Editor),用于对文本文件进行行级别的处理。与 vim 不同,sed 处理时不直接编辑文件,而是将文件的每一行读取到临时缓冲区中(称为“模式空间”或 pattern space),在该缓冲区中执行编辑命令,最后将处理结果输出到屏幕或指定的文件。


工作过程


sed 的工作流程包括以下三个主要步骤:


  1. 读取:sed 从输入流(文件、管道、标准输入)中读取一行内容并存储到临时缓冲区(模式空间)中。

  1. 执行:sed 在模式空间中执行指定的命令,对内容进行相应处理。默认情况下,所有 sed 命令都会顺序执行,除非指定了行的地址范围。

  1. 显示:将修改后的内容输出到标准输出或指定的文件。在输出之后,模式空间被清空并重复上述过程,直至所有输入内容处理完毕。

注意:默认情况下,sed 不会修改源文件内容,除非使用 -i 选项直接编辑文件或使用重定向将输出保存到新文件中。


提高 sed 执行效率的方法


在处理大容量文件时,sed 的执行速度可能会变慢。优化方案:



# 将一个百万行的文件拆分为每个文件10000行的小文件
split -l 10000 largefile.txt smallfile_

# 按行分割
# 用行开分割更直观,推荐工作中使用
split -l -30 test1.txt se

# 按大小分割
split -b 400M test1.txt se



sed 命令格式与选项


格式


`sed ‘/匹配模式/命令 参数’ 文件名`


基本操作格式


sed -e ‘操作’ 文件1 [文件2]
# 使用 -e 选项指定编辑操作

sed -f 脚本文件 文件1 [文件2]
# 使用 -f 选项从脚本文件读取操作

sed -i -e ‘操作’ 文件 [文件2]
# 直接编辑文件(慎用)


执行多条命令


方式一:
sed -e ‘操作1’ -e ‘操作2’ 文件

# 例如
sed -n -e ‘/^r/p’ -e ‘/^b/p’ /etc/passwd

方式二:
sed -e ‘操作1;操作2’ 文件


常用选项








常用操作符(也叫命令)












分隔符 / 格式说明


在 sed 命令的语法规则中,正则表达式通常用正斜杠 / 来分隔,用于将模式和命令分隔开来。


  1. 语法结构:sed 命令的基本格式是 sed ‘s/pattern/replacement/‘ 或者类似的形式,如 sed ‘/pattern/command’。其中,/ 用来分隔正则表达式(模式)和命令部分。例如:



  1. 可以更换分隔符:实际上 / 并不是唯一的,可使用其他字符作为分隔符,只要在整个命令中保持一致。例如,# 可以用作分隔符,适合用于匹配带有斜杠的路径的情况:

sed ‘\\#^/usr/local#d’ file.txt
# # 用于替代 / 作为分隔符。


地址定界


sed 命令中的地址定界(addressing)用于指定在哪些行上应用给定的操作。地址定界可以是具体的行号、行范围或匹配模式。sed 根据这些地址定界确定在哪些行上执行操作。


地址定界的类型


  1. 行号:指定特定的行。


  1. 行范围:指定一个行的范围(从某一行到另一行)。


  1. 匹配模式:基于内容匹配来指定行。


  1. 地址和操作的组合:将操作应用于匹配模式和/或特定行号的组合。


sed 的核心功能


sed 具有增(增加)、删(删除)、改(替换)、查(打印)四大核心功能。


打印功能( p , = , l 命令)


sed 命令可以用来查看文件内容,支持重定向输入和管道符的使用。


sed ‘’ /etc/fstab # 查看文件内容
sed ‘’ < /etc/fstab # 使用重定向输入查看文件内容
cat /etc/passwd | sed ‘’ # 使用管道符查看文件内容


示例


  1. 默认打印方式sed 默认会输出所有内容,使用 -n 选项可以禁止默认输出,配合 p 选项打印指定的行。

sed -e ‘p’ test1.txt
# 默认输出加上’p’会打印两行

sed -n ‘p’ test1.txt
# 使用’-n’禁止默认输出,只打印一行

sed -n ‘2p’ test1.txt
# 打印第二行


  1. 打印行号和内容

sed -n ‘=’ test1.txt # 只显示行号
sed -n ‘=;p’ test1.txt # 显示行号和每行的内容


  1. 寻址打印


sed -n ‘1p’ test1.txt # 打印第一行
sed -n ‘4p’ test1.txt # 打印第四行
sed -n ‘$p’ test1.txt # 打印最后一行



sed -n ‘1,3p’ test1.txt
# 打印1-3行

sed -n ‘5,$p’ test1.txt
# 打印第五行到最后一行

sed -n ‘2,+2p’ test1.txt
# 打印第二行和之后的两行,相当于 2,4p

sed -n ‘3p;5p’ test1.txt
# 打印第三行和第五行



sed -n -e ‘2p’ -e’$p’ test1.txt
# 打印第二行和最后一行

sed -n -e ‘2p’ -e’3p’ test1.txt
# 打印第二行和第三行



sed -n ‘n;p’ test1.txt # 打印偶数行
sed -n ‘p;n’ test1.txt # 打印奇数行


  1. 文本模式过滤行内容打印


sed -n ‘/o/p’ test1.txt
# 打印包含 ‘o’ 的所有行

sed -n ‘/th/p’ test1.txt
# 打印包含 ‘th’ 的所有行



sed -n ‘/^root/p’ /etc/passwd
# 打印以 ‘root’ 开头的所有行

sed -n ‘/bash$/p’ /etc/passwd
# 打印以 ‘bash’ 结尾的所有行

sed -n ‘4,/bash$/p’ /etc/passwd
# 从第四行开始,一直打印到第一个以bash为结尾的所在行



sed -r -n ‘/(99:){2,}/p’ /etc/passwd
# 打印包含有两个 ‘99:’ 的行

sed -r -n ‘/^root|bash$/p’ /etc/passwd
# 打印以 ‘root’ 开头或以 ‘bash’ 结尾的行


删除操作( d 命令)


注意:sed -i 时会对文本进行实际操作,建议对目标文件先进行备份,再进行操作。


示例


  1. 通过行号进行删除

sed ‘d’ test1.txt
# 删除所有行,什么也不打印

sed -n ‘3d;p’ test1.txt
# 删除第三行,打印剩余内容

sed -n ‘5,8d;p’ test1.txt
# 删除5到8行,打印剩余内容

sed -n ‘5,$d;p’ test1.txt
# 删除5到最后一行,打印剩余内容

sed ‘4,6!d’ test1.txt
# 除了4-6行,其他的全部删除
# 如果要生效:sed -i -n


  1. 匹配字符串内容删除

sed ‘/one/d’ test1.txt
# 删除包含 ‘one’ 的行

sed ‘/one/,/six/d’ test1.txt
# 删除 ‘one’ 到 ‘six’ 之间的行

sed ‘/one/,/six/!d’ test1.txt
# 反向删除,除了one-six的行,其余的全部删除

sed ‘/six/!d’ test1.txt
# 反向删除,除了six的行,其余的全部删除


  1. 字符串搭配正则进行删除

sed ‘/^$/d’ test1.txt
# 通过^$,来删除空行;


  1. 删除空行

# 方法一:
grep -v “^$“ test1.txt # 过滤出非空行
# 方法二:
cat test1.txt |tr -s “\n” # 压缩换行符
# 方法三:
sed ‘/^$/d’ test1.txt # 删除空行


替换操作( s , c , y 命令)


格式


sed 使用 s 操作符进行替换:


`行范围 s/旧字符串/新字符串/替换标记`


示例


sed ‘s/旧字符串/新字符串/‘ test1.txt
# 替换第一处匹配

sed ‘s/旧字符串/新字符串/g’ test1.txt
# 替换所有匹配


替换标记和替换命令:




常用替换标记






常用替换命令





特殊转换符号










其他操作符号




示例


  1. 直接替换字符串( s 命令)

sed -n ‘s/root/test/2p’ /etc/passwd
# 指定第二个 “root”,替换为 “test”

sed -n ‘s/root/test/gp’ /etc/passwd
# 所有的 “root” 都替换为 “test”

sed -n ‘/^root/ s/^/#/p’ /etc/passwd
# 以”root”开头的行,替换开头为空的字符为”#“


将文件中“/var/www/”的内容替换为“/etc/”


`sed “s/\/var\/www/\/etc/“ httpd.conf`


  1. 字母字符大小写转换sed 可以用于转换字母的大小写:将大写字母转换为小写:“l&” 是转换小写的特殊符号

sed ‘s/[A-Z]/\l&/g’ test1.txt
# 将所有大写字母转换为小写,
# “l&” 是转换小写的特殊符号,需加转义符 “\“


将首字母转换为大写:“u&” 是转换首字母大写的特殊符号


sed ‘s/[a-z]/\u&/‘ test1.txt
# 将首字母替换为大写,
# “u&” 是转换首字母大写的特殊符号,需加转义符 “\“


**将所有小写字母转换为大写:**末尾加上 “g”


sed ‘s/[a-z]/\\U&/g’ test1.txt
# 末尾加上 “g”,表示全部转换成大写


  1. 字符串和字符位置交换通过正则表达式的分组和引用,sed 可以轻松实现字符串或字符位置的交换。

echo ky29ztt | sed -r ‘s/(ky29)(ztt)/\2\1/‘
# 输出:zttky29

echo ky27yhtdxl | sed -r ‘s/(ky27)(yht)(dxl)/\3\2\1/‘
# 输出:dxlyhtky27

echo ky27yhtdxl | sed -r ‘s/(ky27)(yht)(dxl)/\3\2/‘
# 输出:dxlyht

echo 123abc | sed -r ‘s/(.)(.)(.)(.)(.)(.)/\6\5\4\3\2\1/‘
# 输出:cba321

echo 小明明真的帅 | sed -r ‘s/(.)(.)(.)(.)(.)(.)/\6\5\4\3\2\1/‘
# 输出:帅的真明明小


  1. **整行替换( c 命令)**使用 c 命令可以替换整行的内容。

sed ‘/ONE/c 22’ test1.txt
# 将包含 “ONE” 的行替换为 “22”

sed ‘/TWO/c TEST’ test1.txt
# 将包含 “TWO” 的行替换为 “TEST”


  1. **单字符替换( y 命令)**使用 y 命令对单个字符进行替换,每个字符需要一一对应,不是整体替换。只要有匹配的单字符会全部替换。注意:前后字符串长度需要一致,否则会报错。

sed ‘y/TH/12/‘ test1.txt
# 将 “T” 替换为 “1”,”H” 替换为 “2”


增加功能( a , i , r 命令)


sed 支持在指定行后或前增加内容,或从文件中读取内容插入。


常用增加命令





示例:


###用法一:
sed ‘/three/a 123’ test1.txt
# 在包含 “three” 的行后插入 “123”

sed ‘/three/i 123’ test1.txt
# 在包含 “three” 的行前插入 “123”

sed ‘/three/r test.sh’ 123.txt
# 在包含 “three” 的行后插入 “test.sh” 文件内容

###用法二:使用$符号匹配
sed ‘$r test2.txt’ test1.txt
# 在 test1.txt 最后一行后插入 test2.txt 文件的内容
# $-匹配最后一行,r-读取再插入

sed ‘$a 123’ 123.txt
# 在 `123.txt` 最后一行插入 “123”,a-下一行

sed ‘$i 123’ 123.txt
# 在 `123.txt` 倒数第二行后插入 “123”,i-上一行

sed ‘s/$/ EOF/‘ 123.txt
# 使用替换,在每一行末尾添加 “EOF”


使用 -f 指定命令文件(读取规则)


sed 可以通过 -f 参数指定命令文件来处理另一个文件。


示例1


读取 123.txt 的替换规则应用到 456.txt 。


cat 123.txt
/IPADDR=192.168.233.21/c IPADDR=10.10.10.10

cat 456.txt
IPADDR=192.168.233.21

sed -f 123.txt 456.txt
# 使用 123.txt 的命令处理 456.txt
# 结果将 IP 地址替换为 “10.10.10.10”


示例2


使用 -f 选项从文件 test27.txt 中读取替换规则,并将这些规则应用到 test27sed.txt 文件的内容上。


cat test27.txt
s/ /_/g

cat test27sed.txt
hello world
aaa bbb

sed -f test27.txt test27sed.txt
hello_world
aaa_bbb
# s/ //g:用下划线()替换所有的空格( )。
# / /:匹配空格
# g:全局替换