文本:sad
asd
startpoint:xxxxxx
endpoint:xxxxx
path:xxxx
slack:xxxx
jccj
path:xxxx
zi
startpoint:xxxxxx
endpoint:xxxxx
要求把含有冒号的连续的多行合并成一行,以空格分割:
sad
asd
startpoint:xxxxxx endpoint:xxxxx path:xxxx slack:xxxx
jccj
path:xxxx
zi
startpoint:xxxxxx endpoint:xxxxx
- sed '/:/{:a;N;/\n[^:]*$/!{$!ba};s/\n\([^:]*:\)/ \1/g}' file
[解析]
一开始这问题还有点小棘手,思考再三定下觉得正确的思路后慢慢写,最后还是搞定了。把匹配到冒号的行开始执行死循环,一直用 N 读取下一行,直到读到没有冒号的行,或者读到尾行,才开始替换,把换行替换成空格,这样跳出死循环后,命令执行完了sed会把结果输出。这是总体的思路,细节上几个注意的地方,第一:匹配不包含冒号的行,注意后面加上 $ 边界,表示文本末尾,否则的话前面 pattern space 内的内容也匹配到,sed就会去执行替换,从而失败。第二,如果只是全局替换\n为空格,那么会把最后那行不包含冒号的行也会被替换到同一行内,所以这里要排除最后一个 \n 后不包含冒号内容。第三,用N读取到最后一行,发现没匹配到冒号它又会再次死循环ba跳去N读取下一行,发现没有行可以读取的时候N会中止命令直接结束,那么就不会有后面的替换操作,为了避免这种情况,必须加上尾行的判断,把ba跳转排除尾行。
- sed '/:/{:a;N;/:[^\n]*$/s/\n/ /;ta;P;D}' file
[解析]
这个命令就要短很多了,我老是忘了我们的老朋友,P;D 组合。匹配到冒号的行后,N读取下一样内容,然后尝试替换,如果下一行也是有冒号的行,那么冒号后面到 $ 结束就不会有换行符,替换会成功,ta 跳转去Table a处,又读取下一行,直到读取到不含有冒号的行,那么匹配就会失败,因为该行不含有冒号,正则会匹配到上一行的冒号,那样的话后面必然会出现一个换行符了,所以替换失败,ta不会生效,这时候执行后面的 P 打印 pattern space 的第一行,也就是把含有冒号的行处理为了一整行的那一行,然后 D 删除 pattern space 的第一行。这时候 pattern space 留下的是 "jccj" 这样的内容,那么 D 会跳转命令去行首继续执行,这时候不匹配冒号 "jccj" 就被输出到了屏幕,然后继续后面的操作。
- awk '/:/{i=i?i FS $0:$0;next}{print i?i RS $0:$0;i=0}END{if(i)print i}' file
[解析]
其实awk执行流程更符合我们的编程思维,匹配到冒号的行,就把各行用 FS 空格接起来,直到没有匹配到冒号然后打印出来,并把i变量置零。最后END再判断一下,如果i有内容就打印。
- awk 'ORS=/:/?FS:RS;END{printf RS}' file
[解析]
这个就不说了,秒杀。
阅读(4094) | 评论(0) | 转发(0) |