简介
sed是强大的非交互式的流编辑器, 支持正则表达式, 可直接在控制台命令行或shell脚本中对文本进行过滤, 搜索, 查找, 替换, 插入或删除操作,而不用像vim那样打开文本. sed默认情况下不会修改文件 除非使用shell重定向来保存输出结果.
工作流程
sed逐行处理文件,并打印处理结果. 流程如下:
读取要处理的程序脚本 --- SED PROGRAM
读取一行输入文件内容 --- INPUT : filename line 1
将其复制到一个临时缓冲区,称为模式空间(pattern space)中, --- PATTERN
在模式空间中, 根据提供的命令进行匹配, 并修改数据 --- COMMAND, MATCHED REGEX REGISTERS
将处理结果输出到屏幕(除非有命令删除或取消打印) --- PATTERN
结束本轮循环 --- END - OF - CYCLE
继续读取下一行数据, 重复以上过过程 直到所有数据处理完毕. ---INPUT : filename line 2
语法
sed OPTIONS... [SCRIPT, -f SCRIPT-FILE] [INPUTFILE...]
常用选项/参数
选项/参数 | 说明 |
---|---|
-n, --quiet, --silent | 安静模式,在一般情况所有的 stdin 都会输出到屏幕上, 加入-n 后只打印被sed处理的行 |
-i[SUFFIX], --in-place[=SUFFIX] | 直接修改输入文件的内容,不在屏幕上输出, 如提供后缀SUFFIX 则会在当前目录自动备份源输入文件 |
-e script, --expression=script | 以选项中的指定的script来处理输入文件 |
-E, -r, --regexp-extended | 使用扩展正则 |
-f script-file, --file=script-file | 以选项中指定的script文件来处理输入文件 |
-s, --separate | 将多个文件分别单独处理 |
-u, --unbuffered | 从多个输入文件中加载最少数量的数据, 更频繁地刷新输出缓存 |
-z --null-data | 默认\n分隔行, 如果有-z, 则按空字符分隔每行 |
sed操作命令
操作命令 | 说明 |
---|---|
a \ | append 在指定行后添加文本 \为内嵌文本换行 |
c \ | 用新文本修改替换选定的文本 \为内嵌文本换行 |
i \ | insert 在指定行之前插入文本 \为内嵌文本换行 |
p | 输出当前模式空间的内容 |
d | 删除模式空间内容, 开启新一轮循环 => 删除选中行 |
x | 交换保持空间(hold space)和模式(pattern space)的内容 |
g | 替换模式空间中的内容为保持空间中的内容 |
G | 在模式空间换行, 将保持空间里的内容追加到模式空间 |
h | 替换保持空间中的内容为模式空间中的内容 |
H | 在保持空间换行, 将模式空间里的内容追加到保持空间 |
w | 将当前模式空间内容写入文件 |
W | 将当前模式空间第一行写入文件 |
I | 列出非打印字符 |
n, N | 读取/追加下一行输入, 从下一行开始处理 |
q | 立即结束, 不会再处理其他输入 |
r | 从文件中读行 |
! | 对所选行除外的所有行应用命令 |
s | 替换指定字符 |
--debug | debug 显示处理的全过程 |
sed寻址类命令(Addresses)
如果没有地址, sed命令将应用与所有输入行;
给定一个地址, sed仅会执行与该地址匹配的行.
命令 | 说明 |
---|---|
number | 匹配指定行, 如果有多个输入文件, 行号会累加, 除非使用-s选项 |
first~step | 从first行开始按步长匹配行, addr1 为0时, 从step行开始, 按步长匹配 |
$ | 匹配最后一行 |
/regexp/ | 按正则匹配行 |
\cregexpc | 表示匹配正则那一行,通过\c 和 c 之间的正则来匹配,c 可以是任一字符 |
addr1, addr2 | 匹配从addr1 到 addr2的行, 起始行addr1总会被匹配执行, 无论结束行addr2是否匹配, 即使addr2可能比addr1小; 如果addr2是正则表达式, addr2也不会与addr1匹配冲突.(见实例 13) |
0, addr2 | 仅当addr2为正则时有效, 起始行, 结束行都按addr2规则进行匹配, 如果开始第一行就命中addr2的规则, 则处理第一行后其余行就无法命中匹配, 而不会像addr1, addr2那样匹配addr1后,继续检测结束行addr2的匹配规则 (见实例 14) |
addr1, +N | 从addr1匹配的行开始 到addr1+N 行的范围 |
addr1, ~N | 从addr1匹配的行开始, 逐行匹配, 直到行数为N的倍数 |
使用示例
$ cat input.txt
unix is great os. unix is opensource. unix is free os.
learn operating system.
unix linux which one you choose.
unix is easy to learn.unix is a multiuser os.Learn unix .unix is a powerful.
-
s替换
# 默认每一行只会匹配一次, 替换后便开始读取下一行(开启新一轮循环) $ sed 's/unix/Linux/' input.txt Linux is great os. unix is opensource. unix is free os. learn operating system. Linux linux which one you choose. Linux is easy to learn.unix is a multiuser os.Learn unix .unix is a powerful. #加入g命令, 进行全局修改 $ sed 's#unix#linux#g' input.txt linux is great os. linux is opensource. linux is free os. learn operating system. linux linux which one you choose. linux is easy to learn.linux is a multiuser os.Learn linux .linux is a powerful.
由于是在模式空间中操作并打印, 输出结果实际上并没有更改原输入文件(input file)
$ cat input.txt unix is great os. unix is opensource. unix is free os. learn operating system. unix linux which one you choose. unix is easy to learn.unix is a multiuser os.Learn unix .unix is a powerful.
-
d删除行
$ sed '2,$d' input.txt > output.txt #只保留第一行 ,表示范围 $ sed '1d;3d' input.txt > output.txt #删除第1和第3行, ;表示分隔 $ sed '/learn/d' input.txt > output.txt #删除包含learn的行
-
i, a, c\ 插入替换文本
# i 在第一行前添加2行 $ seq 5 | sed '1i 100\ > 200' > output.txt #显示结果 $ cat output.txt 100 200 1 2 3 4 5 # a 在第三行后追加2行 $ seq 5 | sed '3a 100\ 200' > output.txt #显示结果 $ cat output.txt 1 2 3 100 200 4 5 # c 将第二行替换成200 seq 5 | sed '2c200' > output.txt #显示结果 $ cat output.txt 1 200 3 4 5
-
重定向到输出文件
如果没有指定输入文件 或输入文件是 - , sed会过滤处理标准输入内容, 下面的3行命令等效
$ sed 's/unix/Linux/' input.txt > output.txt $ sed 's/unix/Linux/' < input.txt > output.txt $ cat input.txt | sed 's/unix/Linux/' - > output.txt
-
-n 与 -p 一起使用: 表示只打印匹配或处理过的行.
#打印指定的第2行, 以下命令等效 $ sed -n '2p' input.txt $ head -2 input.txt | tail -1 #单个文件 NR 与 FNR 相同, $ awk 'NR==2' input.txt $ awk 'FNR==2' input.txt
-
存在多个输入文件时, sed 默认将他们视为单一持续的流(strem)来处理, 如加入-s参数,则会按不同文件处理
#准备3个文件 $ echo 'one' > one.txt $ echo 'two' > two.txt $ echo 'three' > three.txt #打印第1行 和最后一行, 三个文件整合成了一个流 $ sed -n '1p; $p' one.txt two.txt three.txt one three #加入-s后, 三个文件被分别处理 $ sed -ns '1p; $p' one.txt two.txt three.txt one one two two three three
-e, ; 连接多个scripts
$ sed -e '3d' -e 's#unix#linux#g' input.txt > output.txt #删除第3行后,再进行替换
$ sed '3d; s#unix#linux#g' input.txt > output.txt # 不用-e, 则需要; 分割
-
-i[SUFFIX ]直接修改原输入文件
$ sed -i.bak 's#unix#linux#g' input.txt #i选项后加入.bak后缀,实现自动对原文件备份 文件名为 input.txt.bak $ cat input.txt #原文件已经被修改 linux is great os. linux is opensource. linux is free os. learn operating system. linux linux which one you choose. linux is easy to learn.linux is a multiuser os.Learn linux .linux is a powerful. #注意: -i 选项 与 -n 选项 不要一起使用 否则如果没有备份, 可能会造成原文件数据丢失 #原因是 -i 是将打印内容写入原文件, -n则是取消打印 一起使用导致 空内容写入原文件 #虽然加入p可以解决文件丢失问题,但依然不建议i, n 一起使用 #错误使用的例子: $ sed -ni.bak 's#unix#linux#g' input.txt $ ll input.txt -rw-rw-r-- 1 dliu dliu 0 Apr 8 10:43 input.txt #input.txt内容都没了!!! $ ll input.txt.bak -rw-rw-r-- 1 dliu dliu 188 Apr 8 10:40 input.txt.bak #好在进行了备份! #解决方案: 以下命令完全等效, 还用啥i + np, 多次一举,风险还大 $ sed -ni.bak 's#unix#linux#gp' input.txt $ sed -i.bak 's#unix#linux#g' input.txt
-
n 从下一行开始执行命令
#如果匹配到free,则下一行的you变成I $ sed '/free/{n;s#you#I#}' input.txt unix is great os. unix is opensource. unix is free os. unix linix which one I choose. unix is easy to learn.unix is a multiuser os.Learn unix .unix is a powerful.
-
--debug 查看执行过程
#查看n的执行过程 $ sed --debug '/free/{n;s#you#I#}' input.txt SED PROGRAM: /free/ { n s/you/I/ } INPUT: 'input.txt' line 1 PATTERN: unix is great os. unix is opensource. unix is free os. COMMAND: /free/ { COMMAND: n unix is great os. unix is opensource. unix is free os. PATTERN: unix linix which one you choose. COMMAND: s/you/I/ MATCHED REGEX REGISTERS regex[0] = 21-24 'you' PATTERN: unix linix which one I choose. COMMAND: } END-OF-CYCLE: unix linix which one I choose. INPUT: 'input.txt' line 3 PATTERN: unix is easy to learn.unix is a multiuser os.Learn unix .unix is a powerful. COMMAND: /free/ { COMMAND: } END-OF-CYCLE: unix is easy to learn.unix is a multiuser os.Learn unix .unix is a powerful.
-
! 跳过所选行
#执行s#unix#linux#g时, input.txt第三行修改后变成 linux linix which one you choose. 语义不对, 怎么解决 ? #方案: 跳过第三行,其余行进行修改,用到!命令 $ sed '3!s#unix#linux#g' input.txt linux is great os. linux is opensource. linux is free os. learn operating system. unix linux which one you choose. linux is easy to learn.linux is a multiuser os.Learn linux .linux is a powerful.
-
步长 first~step
$ seq 10 | sed -n 1~2p #从1开始, 步长为2 => 打印奇数行 1 3 5 7 9 $ seq 10 | sed -n '0~2p' # 打印偶数行 2 4 6 8 10
addr1, addr2
```bash
seq 5 | sed -n '1,3p' #匹配1-3行
1
2
3
$ seq 5 | sed -n '3,2p' #add1的总会被匹配
3
```
-
0, addr2
$ seq 10|sed -n '0, /[0-9]/p' #0, addr2: 一开始第一行就命中了addr2的正则, 其余行就不会命中匹配, 只输入1行 1 $ seq 10|sed -n '1, /[0-9]/p' #addr1, addr2: addr2的规则不影响起始行addr1, 输出第一行后按addr2规则匹配结束行, 为第二行 于是输出1-2行 1 2
-
addr1, ~N
$ seq 20 | sed -n '10,~8p' #从第10行开始逐行匹配, 直到行数为8的倍数(这里为16) 10 11 12 13 14 15 16
-
q 终止处理输入行/结束sed
#打印完前2行后 退出sed执行 $ sed '2q' input.txt unix is great os. unix is opensource. unix is free os. unix linix which one you choose.
参考:
https://man.linuxde.net/sed
http://c.biancheng.net/view/4028.html
https://www.cnblogs.com/ginvip/p/6376049.html