bash sed
| env | version |
|---|---|
| sed | sed (GNU sed) 4.7 |
1 工作原理
sed = stream editor 可以对标准输出和文件进行逐行处理 ### 命令结构
1.1 流程图
1.2 –debug 分析流程
1.2.1 p 打印操作分析
执行结果
SED PROGRAM:
/hello/ =
p
INPUT: 'example.txt' line 1
PATTERN: hello cat
COMMAND: /hello/ =
1
COMMAND: p
hello cat
END-OF-CYCLE:
hello cat
INPUT: 'example.txt' line 2
PATTERN: hello world
COMMAND: /hello/ =
2
COMMAND: p
hello world
END-OF-CYCLE:
hello world
INPUT: 'example.txt' line 3
PATTERN: hot dog
COMMAND: /hello/ =
COMMAND: p
hot dog
END-OF-CYCLE:
hot dog- 第5行, 显示 pattern space buffer的内容,就是行内容
- 显示结果里的第6行
COMMAND: /hello/ =判断pattern space是否包含hello,是的话就打印它的行号 - 第8行
COMMAND: p[addr]是空,就是直接匹配了,直接p操作打印pattern space的内容. - 第11行是 不带-n的 默认行为 打印了pattern space的内容
hello cat
1.2.2 s 替换操作分析
执行结果
SED PROGRAM:
s/hello/xxxx/gp
INPUT: 'example.txt' line 1
PATTERN: hello cat
COMMAND: s/hello/xxxx/gp
MATCHED REGEX REGISTERS
regex[0] = 0-5 'hello'
xxxx cat
PATTERN: xxxx cat
END-OF-CYCLE:
xxxx cat
INPUT: 'example.txt' line 2
PATTERN: hello world
COMMAND: s/hello/xxxx/gp
MATCHED REGEX REGISTERS
regex[0] = 0-5 'hello'
xxxx world
PATTERN: xxxx world
END-OF-CYCLE:
xxxx world
INPUT: 'example.txt' line 3
PATTERN: hot dog
COMMAND: s/hello/xxxx/gp
PATTERN: hot dog
END-OF-CYCLE:
hot dog- 第8行 是
s/hello/xxxx/gp中p这个s的flag的行为(打印pattern space). 注意它其实并不是X,s是X,这个p只是它的flag,只不过行为与身为X的p操作一样.后续再说 - 第9行 显示变化后的 pattern space 的内容给我们看. 这个时候已经被替换了相关的字符串. 如果patttern space 内容有变化会在这里重新显示一次
- 不带-n的默认操作, 打印 pattern space
1.2.3 a 行后插入操作分析
执行结果
SED PROGRAM:
/world/ a\python
INPUT: 'example.txt' line 1
PATTERN: hello cat
COMMAND: /world/ a\python
END-OF-CYCLE:
hello cat
INPUT: 'example.txt' line 2
PATTERN: hello world
COMMAND: /world/ a\python
END-OF-CYCLE:
hello world
python
INPUT: 'example.txt' line 3
PATTERN: hot dog
COMMAND: /world/ a\python
END-OF-CYCLE:
hot dog- 从11-16行可以看到 Pattern space并没有发生变化. (有变化会重新显示一次)
- 15行是 没有-n 的默认行为, 打印Pattern space
- 16行是a 的行为. 它发生在 默认打印pattern space行为的后面
- a的行为: 不改变pattern space , 它会把在该命令后面的文本,在当前CYCLE结束或读取下一行时输出.
- 注意上面的空行3,7,13,20这几行,这是COMMAND本身的一部分. 就是说我们a python后面实际跟着一个换行符,要不然也不会是插入一行了. 所以
SED PROGRAM:后面显示的是2行,包含了一个换行符
1.2.4 i 行前插入操作分析
执行结果
SED PROGRAM:
/world/ i\python
INPUT: 'example.txt' line 1
PATTERN: hello cat
COMMAND: /world/ i\python
END-OF-CYCLE:
hello cat
INPUT: 'example.txt' line 2
PATTERN: hello world
COMMAND: /world/ i\python
python
END-OF-CYCLE:
hello world
INPUT: 'example.txt' line 3
PATTERN: hot dog
COMMAND: /world/ i\python
END-OF-CYCLE:
hot dog- 第14行直接打印了, 可以与a操作 做个对比
- 官方原话:
Immediately output the lines of text which follow this command
1.2.5 H和x操作 与hold space
| X | Description |
|---|---|
H1 |
添加一个换行符到hold space,然后将pattern space 的内容追加到hold space |
x2 |
互相hold space和pattern space的内容 |
d |
删除 pattern space的内容,立刻开始下一次cycle,后续的命令不再执行哦 |
执行结果
SED PROGRAM:
/./ {
H
$! d
}
x
s/^/
START-->/
s/$/
<--END/
INPUT: 'input.txt' line 1
PATTERN: js
COMMAND: /./ {
COMMAND: H
HOLD: \njs
COMMAND: $! d
END-OF-CYCLE:
INPUT: 'input.txt' line 2
PATTERN: vue
COMMAND: /./ {
COMMAND: H
HOLD: \njs\nvue
COMMAND: $! d
END-OF-CYCLE:
INPUT: 'input.txt' line 3
PATTERN: react
COMMAND: /./ {
COMMAND: H
HOLD: \njs\nvue\nreact
COMMAND: $! d
END-OF-CYCLE:
INPUT: 'input.txt' line 4
PATTERN:
COMMAND: /./ {
COMMAND: }
COMMAND: x
PATTERN: \njs\nvue\nreact
HOLD:
COMMAND: s/^/
START-->/
MATCHED REGEX REGISTERS
regex[0] = 0-0 ''
PATTERN: \nSTART-->\njs\nvue\nreact
COMMAND: s/$/
<--END/
MATCHED REGEX REGISTERS
regex[0] = 22-22 ''
PATTERN: \nSTART-->\njs\nvue\nreact\n<--END
END-OF-CYCLE:
START-->
js
vue
react
<--END
INPUT: 'input.txt' line 5
PATTERN: python
COMMAND: /./ {
COMMAND: H
HOLD: \npython
COMMAND: $! d
END-OF-CYCLE:
INPUT: 'input.txt' line 6
PATTERN: php
COMMAND: /./ {
COMMAND: H
HOLD: \npython\nphp
COMMAND: $! d
END-OF-CYCLE:
INPUT: 'input.txt' line 7
PATTERN:
COMMAND: /./ {
COMMAND: }
COMMAND: x
PATTERN: \npython\nphp
HOLD:
COMMAND: s/^/
START-->/
MATCHED REGEX REGISTERS
regex[0] = 0-0 ''
PATTERN: \nSTART-->\npython\nphp
COMMAND: s/$/
<--END/
MATCHED REGEX REGISTERS
regex[0] = 20-20 ''
PATTERN: \nSTART-->\npython\nphp\n<--END
END-OF-CYCLE:
START-->
python
php
<--END
INPUT: 'input.txt' line 8
PATTERN: java
COMMAND: /./ {
COMMAND: H
HOLD: \njava
COMMAND: $! d
END-OF-CYCLE:
INPUT: 'input.txt' line 9
PATTERN: golang
COMMAND: /./ {
COMMAND: H
HOLD: \njava\ngolang
COMMAND: $! d
END-OF-CYCLE:
INPUT: 'input.txt' line 10
PATTERN: rust
COMMAND: /./ {
COMMAND: H
HOLD: \njava\ngolang\nrust
COMMAND: $! d
COMMAND: }
COMMAND: x
PATTERN: \njava\ngolang\nrust
HOLD: rust
COMMAND: s/^/
START-->/
MATCHED REGEX REGISTERS
regex[0] = 0-0 ''
PATTERN: \nSTART-->\njava\ngolang\nrust
COMMAND: s/$/
<--END/
MATCHED REGEX REGISTERS
regex[0] = 26-26 ''
PATTERN: \nSTART-->\njava\ngolang\nrust\n<--END
END-OF-CYCLE:
START-->
java
golang
rust
<--END- 第13行, /./匹配非空行
- 第14行, H指令, 将换行符+pattern space追加到 hold space
- 第15行, 可以看到hold space的内容
- 第16行, d 操作 ,然后17行直接 去下一次 cycle,后续 命令不再执行.
- 第32行, input.txt 第4行是空行, 所以/./ 不匹配, 没有做{}里面的d操作, 则继续后面的指令 x,将hold space和pattern space 互换了.
- 后面是s 替换操作. 最后 不带-n的默认 打印pattern space 操作.
2 OPTION 参数
| OPTION | Description |
|---|---|
-n |
|
-e |
|
-f |
|
-E/-r |
带-E与不带-E的区别 1. 不带的时候 那么{}()|+? 没有特别含义,就是它本身,如果想要变成特殊含义则前面加上\ 2. 带上-E与之相反 |
-i |
|
-s |
|
--debug |
指定多个-e, 就是对读取的行,按顺序进行 script1,然后script2 操作
|无特殊含义,就是它本身,所以没有找到匹配的行.
这里的|表示特殊含义或 ,所以可以正确匹配.
sed -n 's/cat/dog/g;p' example.txt
# 直接修改源文件了, 注意这里就不能再加上;p了. 否则你文件里就重复行了.
sed -i 's/cat/dog/g' example.txt- ==使用-i后面直接带上.bak 来修改文件的同时进行备份.==
# 会先将example.txt 做个备份, 文件名是
sed -i.bak 's/cat/dog/g' example.txt.bak
# 所以 写-i 和其他 -E这种参数时要注意, 不要放在i的后面 ,
# 写成 -Ei而不是-iE 后者是做了备份了.E成了备份文件的后缀名
关于-i的底层逻辑
- 实际是创建了一个临时文件, 将输出写入到该临时文件而不是终端.
- 等到文件读完,会将临时文件rename 为 我们 原本的文件名
3 input-file
4 script
4.1 [addr] 匹配行
- 行号指定区间,多行
- 正则区间 /pattern1/,/pattern2/
匹配到pattern1的行开始到匹配到pattern2的行结束- 如果开始的行没有匹配到,那么就没有匹配到行
- 而到哪一行为止呢? 稍微思考下, 可以得出这样的结论 :
- 如果
到哪行为止没有匹配到, 就意味着一直匹配到最后一行 到哪行为止有多行都能匹配到, 肯定是首先匹配的那一行.
- 如果
多个符合的区间, 就会都匹配上的
- 行号正则混合使用
4.2 X 指令
4.2.1 查 (p)
| X | Description |
|---|---|
p |
|
= |
p
=
4.2.2 增 (a i r w)
| X | Description |
|---|---|
a |
|
i |
|
r |
|
w |
# 在匹配到的hello 行下一行 ,添加 NIHAO 这样一行
# a后面 空格 再跟上你要添加的内容
sed -i '/hello/a NIHAO' example.txt
# 匹配到的每一个行 后都添加一行 内容是hi
sed -i '/hello/,/world/a hi'
# 插入多行.
sed -i '/hello/a\
hi\
how are your' example.txt
# 行前
sed -i '/hello/i NIHAO' example.txt
# 将new.txt 里的内容添加到 包含hello 的行后
sed -i '/hello/r new.txt' example.txt
sed -n '/hello/w new.txt' out.txt4.2.3 删 (d)
| X | Description |
|---|---|
d |
后续的命令不再执行且默认不带-n时的打印处理后的行(pattern space+换行符) 的行为也不会执行. 如果这个默认行为没有取消,那么你不带-n时每次d,都会打印一行空行了 |
4.2.4 改 (s)
| X | Description |
|---|---|
s |
| flags | Description |
|---|---|
i/I |
匹配时忽略大小写 |
| regex | Description |
|---|---|
& |
正则表达式匹配到的所有内容 |
\n (n值为1-9) |
正则表达式里\(\)里匹配到的内容 |
4.2.5 n/N
| X | Description |
|---|---|
n |
如果没有使用参数-n, 则立刻打印处理后的行(pattern space+换行符),然后不管是否使用-n,都将pattern space 替换为下一行的内容,如果没有下一行了,则立刻结束,后续指令不操作. |
N |
追加换行符到pattern space,继续追加下一行的内容 ,如果没有下一行了,则立刻结束,后续指令不操作. |
debug
- 第6-7行,由于这里 不带-n,则立刻打印 pattern space,然后 将pattern space 替换为下一行
- 第8行显示为替换后的 pattern space
- 第9-10行 是p的操作, 打印了 pattern space
- 第13行说明直接读取了文件的第3行, 第15行的n 操作 发现没有下一行了.立刻结束了. 不做后续的p操作.
debug
SED PROGRAM:
2 N
s/\n/--/
INPUT: '2.txt' line 1
PATTERN: HEllo cat
COMMAND: 2 N
COMMAND: s/\n/--/
PATTERN: HEllo cat
END-OF-CYCLE:
HEllo cat
INPUT: '2.txt' line 2
PATTERN: xx hello yyy hello
COMMAND: 2 N
PATTERN: xx hello yyy hello\nhot dog HELLO
COMMAND: s/\n/--/
MATCHED REGEX REGISTERS
regex[0] = 18-19 '
'
PATTERN: xx hello yyy hello--hot dog HELLO
END-OF-CYCLE:
xx hello yyy hello--hot dog HELLO4.2.6 ; 和 {;}
;可以有多个
{}里还可以有{}
/hello/=;p 对与匹配到hello的行执行=指令, p与前面的无关, 它会重新看该行是否匹配它自己的规则.