sed - 文本分析与转换工具 (2) 进阶

  • 原创
  • Madman
  • /
  • 2018-04-10 09:15
  • /
  • 0
  • 214 次阅读

Sed - 文本分析与转换工具 (2) 进阶-min.png

Synopsis: 借助于非常好用的调试工具sedsed,可以很好地理解sed的模式空间和保持空间。在调试模式下,它会读取您的脚本并为其添加额外的命令。当执行时,你可以看到命令之间的数据流,揭示模式空间和保持空间中的缓存数据的真实情况。只有真正掌握两个缓存空间如何交换数据,才能实现sed的高级应用。同时介绍了sed如何操纵多行数据,以及改变执行的流程

sed系列:


1. 调试工具 sedsed

sedsed项目 示例脚本

1. 安装
# wget http://aurelio.net/projects/sedsed/sedsed-1.0
# chmod +x sedsed-1.0
# mv sedsed-1.0 /usr/bin/sedsed

2. 在调试模式下,它会读取您的脚本并为其添加额外的命令。当执行时,你可以看到命令之间的数据流,揭示模式空间和保持空间中的缓存数据的真实情况
# cat test.txt  测试文件原内容
The Linux
System and Linux
...

# cat test.txt | sedsed -d '/Linux$/ {N ; s/\nSystem/ Operating &/ ; P ; D}'
PATT:The Linux$
HOLD:$
COMM:/Linux$/ {
COMM:N
PATT:The Linux\nSystem and Linux$
HOLD:$
COMM:s/\nSystem/ Operating &/
PATT:The Linux Operating \nSystem and Linux$
HOLD:$
COMM:P
The Linux Operating 
PATT:The Linux Operating \nSystem and Linux$
HOLD:$
COMM:D
PATT:System and Linux$
HOLD:$
COMM:/Linux$/ {
COMM:N
PATT:System and Linux\n...$
HOLD:$
COMM:s/\nSystem/ Operating &/
PATT:System and Linux\n...$
HOLD:$
COMM:P
System and Linux
PATT:System and Linux\n...$
HOLD:$
COMM:D
PATT:...$
HOLD:$
COMM:/Linux$/ {
PATT:...$
HOLD:$
...

3. 在缩进模式下,您的脚本被重新格式化为标准间距
# cat myscript.sed
/Linux$/{N;s/\nSystem/ Operating &/;P;D}
# sedsed --indent -f myscript.sed 
/Linux$/ {                             
    N                                  
    s/\nSystem/ Operating &/           
    P                                  
    D                                  
} 

4. 在HTMLize模式下,您的脚本会被转换为美丽的彩色HTML文件,并且所有命令和参数都会被标识以供您欣赏
# sedsed --htmlize -f myscript.sed > sedsed.html

5. 在标记模式中,您可以看到您使用的每个命令的元素
# sedsed -t '/Linux$/ {N ; s/\nSystem/ Operating &/ ; P ; D}'

2. pattern spacehold space

除了sed入门篇里面介绍的pattern space,还有一个叫hold space的缓冲区,它也是默认为空。sed在每次循环(处理完一行)后会清空pattern space,但是不会清空hold space,所以可以用hold space来临时保存一些行内容。sed命令不能直接对hold space中的内容执行命令,但是可以将内容在pattern spacehold space中交换:

  • hpattern space中的内容替换hold space中的内容
  • Hpattern space中的内容追加到hold space中(先追加一个换行符\n)
  • ghold space中的内容替换pattern space中的内容
  • Ghold space中的内容追加到pattern space中(先追加一个换行符\n)
  • x交换pattern space中的内容和hold space中的内容
1. 打印偶数行
# sed -n 'x ; n ; p' books.txt
2) The Two Towers, J. R. R. Tolkien, 352 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
6) A Game of Thrones, George R. R. Martin, 864

2. 打印奇数行
# sed -n 'x ; n ; x ; p' books.txt
1) A Storm of Swords, George R. R. Martin, 1216 
3) The Alchemist, Paulo Coelho, 197 
5) The Pilgrimage, Paulo Coelho, 288

3. 打印包含Paulo的前面一行,即第2、4行
# sed -n '/Paulo/! h ; /Paulo/ {x ; p}' books.txt
2) The Two Towers, J. R. R. Tolkien, 352 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432

4. 先打印包含Paulo的前面一行,再打印包含Paulo的当前行,即2~5行
# sed -n '/Paulo/! h ; /Paulo/ {H ; x ; p}' books.txt
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288
或者:
# sed -n '/Paulo/! h ; /Paulo/{x ; G; p}' books.txt
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288 

5. 先打印包含Paulo的当前行,再打印它的前面一行
# sed -n '/Paulo/! h ; /Paulo/ {p ; g ; p}' books.txt 
3) The Alchemist, Paulo Coelho, 197 
2) The Two Towers, J. R. R. Tolkien, 352 
5) The Pilgrimage, Paulo Coelho, 288 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
或者:
# sed -n '/Paulo/! h ; /Paulo/ {G ; p}' books.txt
3) The Alchemist, Paulo Coelho, 197 
2) The Two Towers, J. R. R. Tolkien, 352 
5) The Pilgrimage, Paulo Coelho, 288 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432

6. 倒序排列输出
# sed '1! G ; h ; $! d' books.txt
6) A Game of Thrones, George R. R. Martin, 864
5) The Pilgrimage, Paulo Coelho, 288 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
3) The Alchemist, Paulo Coelho, 197 
2) The Two Towers, J. R. R. Tolkien, 352 
1) A Storm of Swords, George R. R. Martin, 1216

7. 每行后面追加一个空行
# sed 'G' books.txt

8. 追加两个空行
# sed 'G ; G' books.txt

3. pattern space中的多行命令N/D/P

sed命令是根据换行符的位置来每次读取一行内容然后操作的,如果你要编辑的内容被分成两行或多行,那么就要使用多行命令来将多行内容读取到pattern space再整体进行编辑。

说明: 模式空间包含多行时,正则表达式的 ^$ 的指示意义已经发生了改变,^ 匹配模式空间的开始位置而非行首,$ 匹配模式空间的结束位置而非行尾

3.1 N - 加载下一行

N动作将下一行的内容读取到当前模式空间,但是与n动作不一样的地方是N动作并没有直接输出当前模式空间中的行,而是把下一行追加到当前模式空间,两行之间用换行符\n连接,比如This is line one\nand this is line two

# sed 'N ; s/\n/, /g' books.txt 
1) A Storm of Swords, George R. R. Martin, 1216 , 2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 , 4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage, Paulo Coelho, 288 , 6) A Game of Thrones, George R. R. Martin, 864

3.2 D - 删除多行中的一行

d动作会删除模式空间的所有内容,而D动作是删除当前模式空间中开始位置到\n的内容(即第1行,包含\n),接着不会读取新行,而是在修改后的模式空间内容上重新开始执行操作指令。示例,删除如下文本的多余的空行,确保文本每行内容之间只保留一个空行:

1. 测试文件原内容
# cat test.txt
This line is followed by 1 blank line.

This line is followed by 2 blank lines.


This line is followed by 3 blank lines.



This line is followed by 4 blank lines.




This is the end.

2. 如果使用d命令,奇数的空行被正常处理了只保留一个空行,而偶数的空行被全部删除了(匹配空行后,执行N命令,模式空间只有\n,因为读取空行到模式空间时是没有任何内容的,只有N追加的\n# sed '/^$/ {N ; /^\n$/ d}' test.txt 
This line is followed by 1 blank line.

This line is followed by 2 blank lines.
This line is followed by 3 blank lines.

This line is followed by 4 blank lines.
This is the end.

3. D命令关键在于删除模式空间中开始位置到`\n`的内容后,并不会读取新行,而是重新执行操作指令,此时又匹配/^$/所以先追加\n再读取This line is followed by 3 blank lines.,与/^\n$/不匹配所以输出,此时有\n换行
# sed '/^$/ {N ; /^\n$/ D}' test.txt 
This line is followed by 1 blank line.

This line is followed by 2 blank lines.

This line is followed by 3 blank lines.

This line is followed by 4 blank lines.

This is the end.

3.3 P - 输出多行中的一行

P动作打印模式空间中开始位置到第一个\n为止这部分内容(不包括\n),经常与-n一起使用,如果想改变sed的处理流程时,P一般在N后面,在D前面

# sed -n 'N ; P' books.txt 
1) A Storm of Swords, George R. R. Martin, 1216 
3) The Alchemist, Paulo Coelho, 197 
5) The Pilgrimage, Paulo Coelho, 288

综合示例:

1. 测试文件原内容
# cat test.txt
The Linux
System and Linux
...

2. 详细步骤见下图
[root@External ~]# sed '/Linux$/ {N ; s/\nSystem/ Operating &/ ; P ; D}' test.txt
The Linux Operating 
System and Linux
...

3. 指定-n选项,则不会输出pattern space空间的内容,即最后的"..."不会被输出
# sed -n '/Linux$/ {N ; s/\nSystem/ Operating &/ ; P ; D}' test.txt
The Linux Operating 
System and Linux

4. 流程控制

sed默认是从上往下读取文本行并处理,但像d/n/N/D/P能够在一定程序上改变默认的处理流程。另外,sed还提供了分支 b测试 t两个动作来控制流程,其可以跳转到指定的标签 label位置继续执行命令

4.1 b

:冒号开头定义一个标签label,用b label表示如果匹配则跳转到label所在位置,如果不匹配跳转到脚本的结尾处(Branch to label; if label is omitted, branch to end of script.)

# sed -n 'h;n;H;x;s/\n/, /;/Paulo/!b Print; s/^/- /; :Print;p' books.txt
1) A Storm of Swords, George R. R. Martin, 1216 , 2) The Two Towers, J. R. R. Tolkien, 352 
- 3) The Alchemist, Paulo Coelho, 197 , 4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
- 5) The Pilgrimage, Paulo Coelho, 288 , 6) A Game of Thrones, George R. R. Martin, 864

b后面指定了标签名,则跳转到标签处

:top
command1
command2
/pattern/b top
command3

当执行到/pattern/b top时,如果匹配pattern,则跳转到:top标签所在的位置,继续执行下一个命令command1

b后面没有指定标签名,则跳转到脚本结尾处

/pattern/b
command 1
command 2
command 3

当执行到/pattern/b时,如果匹配pattern,则跳转到最后。这种情况下匹配pattern的行可以避开执行后续的命令,被排除在外

实现类似于if语句的效果:

command1
/pattern/b end
command2
:end
command3

当执行到 /pattern/b end 时,如果匹配pattern,则直接跳转到 :end 标签处,即跳过command2继续往下执行command3;如果不匹配pattern,则顺序执行command2和command3

实现类似于if...else...语句的效果:

command1
/pattern/b dothree
command2
b
:dothree
command3

当执行到/pattern/b dothree时,若匹配pattern则中转到:dothree标签,此时执行command3;若不匹配,则执行command2,然后遇到没有标签名的b,则跳转到最后

4.2 t

t也可以跳转到标签的位置,但是它的跳转是有条件的,只有当一个替换命令s///执行成功后才有条件地跳转到标签。[address]t[label],label 是可选的,如果没有给出label,控制就被转到脚本的结尾处

# echo "123456789abcd" | sed ':loop s/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/ ; t loop'
123,456,789abcd

# echo "123456789abcd" | sed ':loop s/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/ ; b loop'
此时会死循环...
分类: Linux
标签: GNU sed
未经允许不得转载: LIFE & SHARE - 王颜公子 » sed - 文本分析与转换工具 (2) 进阶

分享

作者

作者头像

Madman

如果博文内容有误或其它任何问题,欢迎留言评论,我会尽快回复; 或者通过QQ、微信等联系我

0 条评论

暂时还没有评论.

发表评论前请先登录