# 多行命令
n
命令 -- next
,会将 sed
编辑器移动到数据流中的下一行文本,而不用重新回到命令的最开始执行
sed '/head/{n;d}' data | |
# 当匹配到 head 一行,sed 会马上移动到下一行开头,执行 d 命令 |
N
命令,将数据流中两个文本行合并到同一个模式空间中,两行文本仍以换行符相隔,但是会将两行文本当作一行处理。
cyan@cyan-virtual-machine:~/Templates$ cat data | |
cat | |
cat | |
cat | |
end | |
cyan@cyan-virtual-machine:~/Templates$ sed '/cat/{N;s/\n/ /}' data | |
cat cat | |
cat end |
但是这个命令存在局限,比如前四行, sed
会将第 1,2 行看作整体,第 3,4 行看作整体,如果最后一行是第五行单行, sed
不会检查第五行,直接结束。
N,d
两个命令配合可以实现多行删除,对于匹配到的,模式空间中两行都会删除, D
就只会删除模式空间第一行,第二行被保留。
cyan@cyan-virtual-machine:~/Templates$ cat data | |
cat | |
cat | |
cat | |
cat | |
end | |
cyan@cyan-virtual-machine:~/Templates$ sed "N;/[c,e]*/d" data | |
end | |
# N 和 D 的配合使用,可以删除行前的空白行 | |
cyan@cyan-virtual-machine:~/Templates$ cat data | |
cat | |
dog | |
mouse | |
monkey | |
cyan@cyan-virtual-machine:~/Templates$ sed "N;/ /D" data | |
cat | |
dog | |
mouse | |
monkey |
N,P
命令可以实现多行打印, P
命令只打印模式空间的第一行。
cyan@cyan-virtual-machine:~/Templates$ cat data | |
cat | |
dog | |
mouse | |
monkey | |
cyan@cyan-virtual-machine:~/Templates$ sed -n "4{N;P}" data | |
mouse |
关于 sed
中 p,P
命令的区别,可以参考这篇文章
http://www.136.la/shida/show-410559.html
# 保持空间
模式空间是一块活跃的缓冲区,sed 编辑器还有另一块称作保持空间的缓冲区。对于保持空间,存在 5 条命令,用来将文本从模式空间复制到保持空间。这可以清空模式空间来加载其他要处理的字符串。
h--将模式空间复制到保持空间 | |
H--将模式空间附加到保持空间 | |
g--将保持空间复制到模式空间 | |
G--将保持空间附加到模式空间 | |
x--交换两个空间的内容 | |
sed -n '/first/ {h;p;n;p;g;p}' data |
现在你不用太理解,只需要有这么个空间即可。
# 排除命令
在 sed
基础那篇文章中,提到 !
可以代替 /
sed 's/cat/dog/' data | |
sed 's!cat!dog!' data |
在 sed
中,使用感叹号 !
还可以排除命令,让原本会起作用的命令不起作用,比如在最后一行取消使用 N
命令
sed '$!N;其他命令' data |
现在给出一个例子,通过这个例子,我们会用到模式空间,保持空间以及排除命令
# 逆序打印文本 | |
cyan@cyan-virtual-machine:~/Templates$ echo -n "first | |
> second | |
> third | |
> " > data | |
cyan@cyan-virtual-machine:~/Templates$ sed -n '{1!G;h;$p}' data | |
third | |
second | |
first |
上述命令, G,h
是关于保持空间的命令,每次将数据读取到模式空间,保持空间中的数据都会附加到模式空间 (第一行除外),然后再复制到保持空间。当然, Linux
命令 tac
可以直接逆序文本,其实 tac
就是 cat
反着写。
等一下,我好像还没讲过什么是模式空间: sed
每次读一行,都会把这一行数据读到模式空间,在使用命令处理数据,在打印到标准输出。
关于逆序打印文本,具体我们可以看下图
如果你真的理解了,那么你就知道,这个命令也可以实现逆序
sed -n '{1!G;$!h;$p}' data |
# 分支
分支命令共有两条:分支(b)和替代分支(t)。
# b 命令
基于地址,地址模式或地址区间排除整块命令: [address]b [label]
。
address
决定哪些行触发分支命令。 label
参数定义了要跳转的位置,如果此处没有 label
参数,跳转命令会跳转到脚本结尾(注意,是命令脚本的结尾)。
sed '{2,3b ; s/This is/Is this/ ;s/line./test?/}' data |
sed
还可以使用标签,使用标签后,只会跳过部分命令,也就是标签之前的命令。直到这里你可能不是很懂,我要提醒的是,在 sed
中引入分支,我建议将命令放在 .sed
命令脚本中,这样使用起来才方便。
# 假设我们需要都数据文件进行处理,一行数据中一旦出现 cat 这个单词,我们就打印其所在行号 | |
# 否则,就打印该行 | |
# command.sed | |
/cat/b error_print | |
/**/b true_print | |
: error_print | |
= | |
b # 跳到结尾,不然会执行 true_print 的语句 | |
: true_print | |
p | |
b |
更改一下 data
的内容,执行 sed
命令
cyan@cyan-virtual-machine:~/Templates$ echo -n "dog | |
> monkey | |
> cat | |
> mouse | |
> " > data | |
cyan@cyan-virtual-machine:~/Templates$ sed -n -f command.sed data | |
dog | |
monkey | |
3 | |
mouse |
如果你把标签放到分支跳转的前面,很容易形成死循环。比如,通过 sed
将数据中的 ,
全部删除
cyan@cyan-virtual-machine:~$ echo "This, is, a, test, to, remove, commas." | sed -n '{ | |
> :start | |
> s/,//p | |
> b start | |
> }' | |
This is, a, test, to, remove, commas. | |
This is a, test, to, remove, commas. | |
This is a test, to, remove, commas. | |
This is a test to, remove, commas. | |
This is a test to remove, commas. | |
This is a test to remove commas. | |
^C | |
# 每次去掉一个,然后跳回 start 标签处 | |
# 当然,直接使用 g 选项 | |
cyan@cyan-virtual-machine:~$ echo "This, is, a, test, to, remove, commas." | sed -n 's/,//gp' | |
This is a test to remove commas. |
上述例子,为了解决死循环,可以指定一个地址模式
cyan@cyan-virtual-machine:~$ echo "This, is, a, test, to, remove, commas." | sed -n '{ | |
:start | |
s/,//p | |
/,/b start | |
}' | |
# 只有再次匹配到,才会跳转 |
你也可以看一下这篇文章。
https://blog.csdn.net/m0_51642814/article/details/111461137
# t 命令
测试命令 ( t
) 也可以用来改变 sed
执行流程,根据测试条件跳转,而不是地址: [address]t [label]
。
如果替换命令匹配并替换了一个模式,测试命令就会跳转到指定标签,否则不会跳转。
cyan@cyan-virtual-machine:~$ echo "This, is, a, test, to, remove, commas." | sed -n '{ | |
:start | |
s/,//p | |
t start | |
}' | |
This is, a, test, to, remove, commas. | |
This is a, test, to, remove, commas. | |
This is a test, to, remove, commas. | |
This is a test to, remove, commas. | |
This is a test to remove, commas. | |
This is a test to remove commas. | |
# 最后一次匹配失败,停止跳转 |
# 模式替代
&
符号,该符号可以用来代表替换命令中的匹配的模式,比如我需要匹配 hello
这个字符串,那么我就可以用 &
来代替 hello
。
cyan@cyan-virtual-machine:~$ echo "The cat is cute." | sed 's/cu[^\.\ ]*/"&"/' | |
The cat is "cute". |
&
在使用正则表达式时十分方便,因为我们也不知道匹配到的模式到底是什么,我们可以直接通过 &
拿到我们匹配到的模式。
替代单独单词: &
符号提取匹配替换命令指定模式的整个字符串,如果想要提取独立的单词,需要使用 ()
。
echo "The system Adminstrator manual" | sed ' | |
> s/\(system\) Adminstrator/\1 user/' | |
The system User manual |
被使用时,圆括号定义了替换模式中的子模式,并使用 \1,2,3..
来表示,在替换命令中使用圆括号时,
必须使用转义字符将它们标示为分组字符而不是普通的圆括号。
所以最开始的例子我们也可以这么写
cyan@cyan-virtual-machine:~$ echo "The cat is cute." | sed 's/\(cu[^\.\ ]*\)/"\1"/' | |
The cat is "cute". |
最后再举一个例子:每三位添加逗号 (类似于,金钱金额分隔计数)
cyan@cyan-virtual-machine:~$ echo $input | sed '{ | |
> : start | |
> s/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/ | |
> t start | |
> }' |
这里说明一下, grep
和 sed
默认不支持 ERE
-- 扩展正则表达式,如果要使用, grep
需要加 -E
选项, sed
需要使用 -r
选项。如果不加选项还想使用 {}
,就要加转义字符 \{m\}
。
在给例子之前,我需要提示一下,我们上面使用 ()
其实就是扩展正则表达式里面的东西,因为之前没有使用 -r
选项,所以需要使用转义字符。
cyan@cyan-virtual-machine:~$ echo $input | sed -r ' | |
: start; | |
s/(.*[0-9])([0-9]{3})/\1,\2/; | |
t start; | |
' | |
10,913,013 |
# 最后
这里有一篇求问博客,是关于 sed
和正则表达式问题的,你能先不看评论区,自己找到博主提出的问题吗?要是你能自己解决,那更是最好的。
https://oomake.com/question/4296530