一、sed 概述
- sed 是一个流编辑器,用于在输入流(文件或管道中的输入)上执行基本文本转换。
- sed 能够对文本文件进行增删改查等操作。
- sed 拥有两个缓冲区,活跃模式空间(active pattern space)与辅助保持空间(auxiliary hold space), 简称为活跃区和暂存区,且这两个缓冲区默认都为空。
- sed 的基本操作只需要用到活跃区,sed的高级操作需要活跃区与暂存区的相互配合。
- 在 sed 的基本操作中,sed 从输入流中得到当前处理的行,会先删除结尾的换行符,存储在一个临时缓冲区,即活跃区;然后 sed 会在活跃区中处理文本,处理完成后加上换行符,并且传送到 stdout (如果没有-n选项),再接着处理下一行,如此循环往复,直至文件末尾,这就是 sed 的基本工作原理。由此可见,sed 在默认情况下是不修改原文件的。
- 除非使用特殊命令 (如 “D”), 否则活跃区的数据将在两个周期之间被删除。
- 在 sed 的高级操作中,多了一个暂存区,暂存区是与活跃区进行交互的,且以活跃区为主,暂存区为辅,sed 匹配的内容最终都得经由活跃区传输至 stdout 。
- sed 的完整语法是
sed OPTIONS… [SCRIPT] [INPUTFILE…]
二、sed 命令行参数
# 测试数据
# 生成1到100
seq 1 100 > nums.txt
cat>words.txt<<-EOF
hello world
Common methods to solve matrix related problem include DFS, BFS, dynamic programming, etc.
hello123 world123
-hello-
_hello_
EOF
# 生成ASCII表中A到z,包含A-Za-z
printf "%s\n" {A..z} > chars.txt
cat>command.txt<<-EOF
pwd
echo "hello world"
EOF
- -n 静默模式,禁止自动打印到标准输出
- -e script 可以多次使用-e,将命令加入命令集。在活跃区,命令集会运行处理输入
sed -n -e '1,3p' -e '2,4p' nums.txt
- -f script-file 将命令写入文件,使用-f,加入命令集
- -i[SUFFIX] 原地编辑文件
- GUN sed会输出内容发送到临时文件,而不是发送到标准输出,当处理完输入文件后,临时文件会重命名为输入文件的名字
- 如果提供SUFFIX,那就会在重命名前,将输入文件重命名作为备份。
- -i后不能有其他短选项,因为如果有会被当做SUFFIX
# 这样会出现问题,生成nums.txtn的备份文件,而-n也没有生效 sed -in '1,3p' nums.txt # 可以改成这样 sed -ni '1,3p' nums.txt # 或 sed -n -i '1,3p' nums.txt # 或 将名字备份为nums.txt.bak sed -n -i.bak '1,3p' nums.txt
- -E -r 使用拓展正则
- -z 和grep -Z类似,常用来处理文件名带空格的文件
三、 sed 脚本
sed 脚本命令的语法为
[addr]X[options]
X是sed单字符的命令;addr是可选的行地址,如果指定,则在匹配的行执行命令X;options是一些sed命令需要的参数。
- addr (没有addr就默认是所有行)
- $ 最后一行
sed -n '$p' nums.txt
- first~step 首行与步进,例如 1~2 就是奇数行, 2~2就是偶数行, 3~3就是3,6,9…
sed -n '1~2p' nums.txt
- addr1, addr2 addr1和addr2可以是正则表达式和数字。如果addr2是正则,那么检查结束行是从addr1匹配的行后开始,范围至少两行(输入流结束除外)
sed -n '1,3p' nums.txt sed -n '2,/1/p' nums.txt # 至少两行 sed -n '2,/[0-9]/p' nums.txt
- /regexp/ 所有匹配正则的行
sed -n '/1/p' nums.txt
- 0,/regexp/ 没有第0行,地址0只是为了处理在addr2与输入第1行匹配的情况,其他与1,/regexp/相同
sed -n '0,/1/p' nums.txt sed -n '1,/1/p' nums.txt
- addr1,+N 匹配addr1,然后N行
sed -n '1,+5p' nums.txt # 所有匹配1的行加上后5行 sed -n '/1/,+5p' nums.txt
- addr1,~N 匹配addr1,然后到N的倍数行
sed -n '/1/,~4p' nums.txt
- ! 在上面的地址后加一个!,表示相反匹配
sed -n '/1/,~4!p' nums.txt
- $ 最后一行
- X
- a text 在行下方添加文本
sed '1a hello\nworld' nums.txt
- b label 无条件调到label
- c text 替换行文本
sed '1c hello\nworld' nums.txt
- d 删除活跃区内容,立即开始下个循环
sed '1,3d' nums.txt
- D 如果活跃区包含换行符,则删除第一行,包含换行符。如果不包含换行符,则和d一样
sed 'N;$!D' nums.txt
- e 执行在活跃区的shell命令
sed 'e' command.txt
- e command 执行command
# 使用e pwd可以在每行前输出前执行命令 sed 'e pwd' command.txt
- F 打印当前输入文件的名字
sed 'F' nums.txt command.txt
- g 将活跃区内容替换为缓存区内容
- G 将活跃区内容加上换行符,然后将暂存区内容追加到活跃区
- h 将暂存区内容替换为活跃区内容
- H 将暂存区内容加上换行符,然后将活跃区内容追加到暂存区
- i text 在行的上方添加文本
sed '1,3i hello\nworld' nums.txt
- n 跳过行
# 两个n跳过2行,每3行执行p sed -n 'n;n;p;' nums.txt
- N 向活跃区添加换行符,接着再把下一行加进去。
sed 'e echo ---' nums.txt sed 'N;e echo ---' nums.txt sed 'N;N;e echo ---' nums.txt
- p 打印活跃区内容
sed -n '1,10p' nums.txt
- P 打印活跃区的第一行
# 每两行打印第一行 sed -n 'N;P' nums.txt
- q[exit-code] 退出sed
# 到第2行退出sed sed '2q10' nums.txt echo $?
- r filename 读文件
# 每行都会读command.txt,并默认打印出来 sed 'r command.txt' nums.txt
- s/regexp/replacement/[flags] 替换字符
- g 全局替换
- number 第number次匹配才替换
- p 如果进行了替换,则打印活跃区内容
- w filename 如果进行了替换,则将结果写入filename
sed 's/1/a/' nums.txt sed 's/1/a/2' nums.txt sed -n 's/1/a/p' nums.txt sed -n 's/1/a/2p' nums.txt
- w filename 将活跃区内容写入文件
sed -n 'w file.txt' nums.txt
- x 交换活跃区与暂存区内容
- y/src/dst/ 将活跃区的内容,按照匹配src的字符转化dst相同位置的字符
sed 'y/123/abc/' nums.txt
- z 清空活跃区内容
- # 注释,直到下一行
- { cmd ; cmd … } 命令组
sed -n '1p;2p;100p' nums.txt sed -n '1{s/1/a/;p}' nums.txt
- = 打印当前输入行数
sed -n '=' nums.txt
- : label 给分支命令(b, t, T)指定label位置
# 定义标签t;使用N输入两行;将\n替换为,;使用b跳到标签t循环 # 将所有换行替换为, sed ':t;N;s/\n/,/;b t'
- a text 在行下方添加文本
参考链接: