sed 循环语句
循环 其实就是一种重复,在满足指定的条件下,重复的做某些事情。就好比如只要时间没到 18:30,那么我们一直在重复的上班。
和其它语言一样,sed 也有循环语句,也有条件判断分支语句。
只是 sed 的循环语句真的很反人类,难记又难懂。
本章节我们就来揭开着难记又难懂的语法。
sed 中的循环语句没有 for 、loop、while 这些关键字,而是和 C 语言 语句有点像。
sed 也有标签 ( label ) 这个概念,而且可以设置标签。
sed 的循环,就是不断跳转到标签标记的行并继续执行其余命令来实现的。
sed 语言使用 冒号(:
) 来实现标签名。
sed 中设置 标签 ( label ) 的语法如下:
:label :start :end :up
看到这种语法是不是很想打人,奇怪又难记。
定义了标签之后,如果要跳转到某个标签名,可以使用 t
命令。
t
命令的语法格式为
t [label_name]
其中 [label_name]
为要跳转到的标签名。这是一个可选项,如果忽略,那么 sed 会跳转到 sed 命令文件的末尾,也就是结束所有 sed 命令。
sed 循环语句
sed 中的循环语句的一般流程如下:
- 先使用标签语法
:<label>
定义一个标签label
。 - 然后定义条件为真时要执行的语句,也就循环语句的代码。
- 最后使用
<condition>t
命令判断循环条件condition
的真假,如果为真则跳转到刚刚定义的标签label
处,为假则继续往下执行语句。
因此,一个简单的 sed 循环语句的语法格式如下
:label some_code_here /<pattern/t label
当然了,我们也可以对条件取反,也就是条件测试不通过时才跳转,这时候就要用到逻辑非运算符 !
了,具体的语法格式如下
:label some_code_here /<pattern/!t label
范例
看了有点复杂啊,我们来写一个范例吧。不过呢,看了范例感觉更复杂...五味杂陈
我们下来看看我们要处理的数据文件,是当前目录下的一个叫 data.txt
的文件,内容如下
I am studing sed I am www.twle.cn I am a no-work-men I am so handsome
就是一些 我是... 的语句。
这时候,我想再说一次,我是傻逼,竟然学这么复杂的 sed 语言。
这个范例,我们需要做的就是把相邻的两行组合在一起,也就是把第一行和第二行组合在一起,第二行和第三行组合在一起...,然后把行中的换行符(\n
)替换为 冒号(:
)。接着查找行中是否有 twle
字符串,如果有的话在行的开头追加四个 ----
。如果没有则直接跳转到 Print
标签处直接输出。
这里我们并不是用条件判断来实现一次性追加四个 -----
,而是使用循环语句,一次只追加一个 -
。
要实现的效果如下
I am :studing sed ----I am :www.twle.cn I am :a no-work-men I am :so handsome
这个效果,用文字描述真的很简单,可是,实现的代码却有点复杂了
[www.twle.cn]$ sed -n ' h;n;H;x; s/\n/:/ :Loop /twle/s/^/-/ /----/!t Loop p' data.txt
运行上面的 sed 程序,输出结果如下
I am :studing sed ----I am :www.twle.cn I am :a no-work-men I am :so handsome
看到上面代码的第一眼,我怎么觉得所有字母都认识,但是放到一起就不认识了呢
-
第一行
h;n;H;x
语句用于把相邻的两行放到一起h
命令拷贝模板块的内容到内存中的缓冲区n
命令读取下一个输入行,用下一个命令处理新的行而不是第一个命令H
命令追加模板块的内容到内存中的缓冲区x
命令表示互换模板块中的文本和缓冲区中的文本
-
第二行
s/\n/, /
把模板块的文本中的 换行符(\n
) 替换成:
。 -
第三行
:Loop
定义了一个标签Loop
。 -
第四行是模式查找和替换语句,首先
/twle/s
用于查找字符串twle
。如果找到则运行后面的语句^/-/
就是在行的开头插入一个-
。 -
第五个命令是一个 条件测试 语句,如果没找到
----
则跳转到标签Loop
,如果找到则继续执行。 -
第六个命令,
p
命令,想必你是知道的,是 输出命令。
上面的 sed 程序,为了方便阅读,我们把每一个 sed 命令都放在了单独的一样。其实更多时候,我们会把它们放到一行上,多条 sed 命令之间使用 分号(;
) 分隔。
就像下面这样
[www.twle.cn]$ sed -n 'h;n;H;x; s/\n/, /; :Loop;/twle/s/^/-/; /----/!t Loop; p' data.txt
运行上面的 sed 程序,输出结果如下
I am : studing sed - I am : www.twle.cn I am : a no-work-men I am : so handsome
疑问?
对于上面这个循环程序,不知道你是不是有和我当初一样的疑问?
为什么不会陷入死循环?
面对组合后的第一行文本 I am :studing sed
,显然是不满足替换的,也就不会在开始添加四个 ----
,那么条件测试就一定不会通过,不会通过就会回到 Loop
然后一直死循环下去?
这个问题,我不知道要如何解释,我么把源程序改一下,改成
sed -n ' h;n;H;x; s/\n/:/ :Loop p /twle/s/^/-/ /---------/!t Loop ' data.txt
也就是说,我们只在循环里输出一次
输出结果如下
I am :studing sed I am :studing sed I am :www.twle.cn -I am :www.twle.cn --I am :www.twle.cn ---I am :www.twle.cn ----I am :www.twle.cn -----I am :www.twle.cn ------I am :www.twle.cn -------I am :www.twle.cn --------I am :www.twle.cn I am :a no-work-men I am :a no-work-men I am :so handsome I am :so handsom
大家看到什么结果了没有?
sed 会统计 t
命令的失败次数,如果超过 2 次失败,则不会继续测试了....