# sed

# 定义

sed(Stream Editor)流编辑器,对标准输出或者文件逐行进行处理

# 语法格式

  • pattern 是匹配的规则,可选,如果不选,则每一行都执行

# 第一种语法格式

stdout | sed [option] “pattern command”

# 第二种语法格式

sed [option] “pattern command” file

# 选项 option

  • sed 默认会打印源文件行,-n 可以只打印模式匹配行

  • 如果有多个匹配条件的话,要加多个-e,只有单个匹配条件的话,-e 是默认的,不用添加

选项 含义
-n 只打印模式匹配行
-e 直接在命令行进行 sed 编辑(单个条件默认添加)
-f 匹配命令保存在文件中,指定该文件执行
-r 支持扩展的正则表达式 (Linux)
-E 支持扩展的正则表达式 (Maxos)
-i 直接修改文件内容 (Linux)
-i ‘path’ 直接修改文件内容 (强制填备份文件路径进行备份,不备份填''字符串)(Linux)

sed.txt

i love cw
cw love me
we are family
we love each other
to the world end

sed.sh

  • 这里的 p 相当于一个 command,是打印的意思

  • -n 就是一个 option

  • "/cw/p"中的/cw/就是 pattern,可以是字符串匹配,也可以是正则,都写在//(正则)中

  • ⚠️ macOS 中-i 必须带-e 或者 跟一个"",表示空备份(macOS 中强行要求备份),也可以在""中写备份的文件名,做备份,否则会报 unterminated substitute pattern

sed "p" sed.txt
# i love cw
# i love cw
# cw love me
# cw love me
# ww are family
# ww are family

sed -n "p" sed.txt
# i love cw
# cw love me
# ww are family

sed -n "/cw/p" sed.txt
# cw love me
# ww are family

# 多个匹配条件
sed -n -e "/cw/p" -e "/we/p" sed.txt
# i love cw
# cw love me
# we are family
# we love each other

# 等价于
sed -nE "/cw|we/p" sed.txt

# 直接替换文本内容
sed -n -i -e "s/like/love/g;p" sed.txt
# 或者
sed -n -i "" "s/like/love/g;p" sed.txt

# pattern 详解

  • 这里的 command 是指满足 sed 的操作命令,比如 p 代表打印

# pattern 用法表

匹配模式 含义
10command 匹配到第 10 行
10,20command 匹配第 10-20 行
10,+5command 匹配到 10-15 行 (maxos 中不能这么用)
/pattern1/command 匹配到 pattern1 的行 (用得最多)
/pattern1/,/pattern2/command 从匹配到 pattern1 的行 开始,知道匹配到 pattern2 的行结束(用得最多)
10,/pattern1/command 从第 10 行开始匹配,直到匹配到 pattern1 的行结束
/pattern1/,10command 从匹配到 pattern1 的行开始,直到第 10 行结束
# 打印文件的第3行
sed -n "3p" sed.txt

# 打印文件的第2-4行
sed -n "2,4p" sed.txt

# 打印文件以we开头的行
sed -n "/^we/p" sed.txt

# 匹配从i开头的行到we开头的行
sed -n "/^i/,/^we/p" sed.txt

# i love cw
# cw love me
# we are family

# 编辑命令详解

  • macOS 上对 a 和 i 有很多坑,具体可以参照macOS 上 i 和 a 的坑

  • macOS 上 s/old/new/ig 中没有 i 这个选项

  • 多个命令中间用 ; 隔开

  • ⚠️ 在使用正则的时候有很多坑,不一定所有的正则都适用

  • macOS 中 s/old/new/与其他非s/old/new/内置支持的编辑命令连用需要用;分开并写在最后,以把s/old/new/当作一个单独的编辑命令,如下

sed -i "" "s/love/like/;=" sed.txt

其他的编辑命令则不需要

sed -n "/love/=" sed.txt
  • 使用变量替换的时候,替换规则必须用双引号,或者使用单引号将变量扩起来
old_str=love
new_str=LOVE

sed -i '' "s/$old_str/$new_str/g" sed.txt
# 等价
sed -i '' 's/'$old_str'/'$new_str'/g' sed.txt

# 编辑命令对照表(主要)

  • ^一般表示开头,$表示结尾,例如$d 则表示删除到最后一行

  • /^$/command 表示操作空行 ^表示从开头$表示直接到结尾,中间没有任何字符则表示空行

  • /[:blank:]*/command 表示对多个空格进行 command

类别 编辑命令 含义
查询 p 打印
增加 a content 行后追加 content
增加 i content 行前追加 content
增加 r 外部文件读入,行后追加
增加 w 匹配行写入外部文件
删除 d 删除
修改 s/old/new 将行内第一个 old 替换为 new
修改 ns/old/new 将第 n 行内第一个 old 替换为 new
修改 s/old/new/g 将行内全部 old 替换为 new
修改 s/old/new/m 将每一行内第 m 个 old 替换为 new
修改 ns/old/new/m 将第 n 行内第 m 个 old 替换为 new
修改 s/old/new/ng 将行内第 n 个 old 开始全部替换为 new (Linux)
修改 s/old/new/ig 将行内全部 old 替换为 new,忽略大小写 (Linux)
修改 /regular/s/old/new/g 满足 regular(满足所有匹配模式)的行中所有 old 替换成 new

# 编辑命令对照表(其他)

类别 编辑命令 含义
其他 # 显示匹配内容的行号(Linux)
其他 # 在每一行的前面插入一行作为该行的行号(macOS)
  • ⚠️ 一般情况下,编辑命令可以用单双引号,但是含有$等特殊字符表达特殊含义的时候必须使用单引号,例如
sed -i '' '1d' sed.txt # 正确
sed -i '' '/^we/,$d' sed.txt # 正确
sed -i '' "/^we/,$d" sed.txt # 错误,$d被当成变量了
# 删除第一行并打印(不修改源文件)
sed -n "1d;p" sed.txt

# 直接删除源文件第一行
sed -nie "1d" sed.txt

# 直接删除源文件第一至三行
sed -nie "1,3d;p" sed.txt

# 删除以c开头到we开头的行(不修改源文件)
sed -n "/^c/,/^we/d;p" sed.txt

# 删除以we开头的行致末尾
sed -i '' '/^we/,$d' sed.txt

# 删除#相关的注释和空行
sed -i '' '/[:blank:]*#/d;/^$/d' sed.txt

# 把sed-command.tx文件里面的内容放在sed.txt中以i开头的行后面
sed -i "" '/^i/r sed-command.txt' sed.txt

# 把符合条件的行保存在sed-save.txt中
sed -i "" '/^i/w sed-save.txt' sed.txt

# 将所有like替换成love
sed -n -i "" "s/like/love/g;p" sed.txt

# 将第二行的love换成like
sed -i "" "2s/love/like/" sed.txt

# 将第一行的第二个love替换成like
sed -i "" "1s/love/like/2" sed.txt

# 将每一行的第二个love替换成like
sed -i "" "s/love/like/2" sed.txt

# 将以we开头的行中所有love替换成love much
sed -i '' '/^we/s/love/love much/g' sed.txt

# 将满足cw的行到we的行之间的所有行中love换成ai
sed -i '' '/cw/,/we/s/love/ai/g' sed.txt

# 输出匹配love行的行号
sed -n "/love/=" sed.txt

# 反向引用

  • 语法 1:使用&代表匹配内容

  • 语法 2:使用\1 代表匹配内容,前提是匹配规则中需要用()扩起来代表\1 的内容(括号要转义)

  • 语法 2 更灵活,可以匹配任意位置和数量的,使用()扩起来,多个使用\1、\2...即可

sed.txt

i lo11ves cw LOVE
cw lo22ves me
we are family
we lo33ves each other lo44ves
to the world end

# 将所有行匹配lo..ve的替换成lo..ves
sed -i "" "s/lo..ve/&s/g" sed.txt

# 等价于
sed -i "" "s/\(lo..ve\)/\1s/g" sed.txt

# 灵活匹配替换位置,替换lo\(..\)ve为lo..o
sed -i "" "s/lo\(..\)ve/lo\1o/g" sed.txt

# 使用更多个括号匹配
sed -i "" "s/lo\(..\)v\(e\)/\1 and \2/g" sed.txt

i 11 and e cw LOVE
cw 22 and e me
we are family
we 33 and e each other 44 and e
to the world end

# 使用*作匹配的时候&只能取到*之前的内容
sed -i "" "s/lo*/&123/g" sed.txt

i lo12311ve cw LOVE
cw lo12322ve me
we are famil123y
we lo12333ve each other lo12344ve
to the worl123d end
  • ⚠️mac 的坑
# Linux
sed -nie "/^we/a 123" sed.txt

# Mac这么写才相当于Linux的
sed -i '' "/^we/a\\
123
" sed.txt

# 这种写法会插在we行的开头
sed -i '' "/^we/i\\
123" sed.txt

# 这种写法会插在we行上一行
sed -i '' "/^we/i\\
123
" sed.txt

# 读取sed-command.txt的内容添加到以i开头的行后面
# maxos中如果sed-command.txt末尾没有空行,那么会贴合源文件内容
sed -i "" '/^i/r sed-command.txt' sed.txt

## sed-command.txt
#/cw/p
# 123

i love cw
/cw/p
123cw love me
we are family
we love each other
to the world end

# maxos中如果sed-command.txt末尾有空行,那么会贴合源文件内容(该表现与Linux一致)
sed -i "" '/^i/r sed-command.txt' sed.txt

i love cw
/cw/p
123
cw love me
we are family
we love each other
to the world end

# maxos千万不要这么写
sed -n -i "" "s/love/like/g" sed.txt # 这么写加上了 -n 会全部替换为空文本
# 正确写法-将文本中全部行的love替换成like
sed -i "" "s/love/like/g" sed.txt

# 忽略大小写只能通过正则扩展去,因为s/old/new/ig中没有i(Linux)这个选项
sed -Ei "" "s/love|LOVE/like/g" sed.txt

# `s/old/new/`与其他非`s/old/new/`内置支持的编辑命令连用需要用;分开并写在最后,以把`s/old/new/`当作一个单独的编辑命令
# 在每一行的前面插入一行作为该行的行号
sed -i "" "s/love/like/;=" sed.txt