Blog

删除开头的空行

Content #

数据文件开头有多个空行也很烦人。将数据从文本文件中导入数据库时,空行会产生一些空项,涉及这些数据的计算都无效。

删除数据流起始处的空行不难。下面是实现该功能的脚本:

/./,$!d

这个脚本用地址区间来决定要删除哪些行。这个区间从含有字符的行开始,一直到数据流结束。在这个区间内的任何行都不会从输出中删除。这意味着含有字符的第一行之前的任何行都会被删除。

From #

Linux命令行与shell脚本编程大全

删除连续的空行

Content #

删除连续空行的最简单方法是用地址区间来检查数据流。删除连续空行的关键在于创建包含一个非空行和一个空行的地址区间。如果sed 编辑器遇到了这个区间,它不会删除行。但对于不属于该区间的行(两个或更多的空行),则执行删除操作。

下面是完成该操作的脚本:

/./,/^$/!d

指定的区间是/./到/^$/。区间的开始地址会匹配任何至少含有一个字符的行。区间的结束地址会匹配一个空行。在这个区间内的行不会被删除。

管文件的数据行之间出现了多少空行,在输出中只保留行间的一个空行。

From #

Linux命令行与shell脚本编程大全

创建滚动窗口(rolling window)

Content #

如何用美元符号来显示数据流末尾的若干行呢?答案是创建滚动窗口(rolling window)。

滚动窗口通过N命令将行合并,是一种检查模式空间中文本行块的常用方法。N命令会将下一行文本附加到模式空间中已有文本行之后。一旦模式空间中有了一个包含10行的文本块,就可以使用美元符号来检查是否已经处于数据流的尾部。如果不是,就继续向模式空间增加行,同时删除已有的行(记住,D命令会删除模式空间的第一行)。

通过循环N命令和D命令,你向模式空间的文本行块增加新行的同时也删除了旧行。分支命令非常适合这个循环。要结束循环,只需识别出最后一行并用退出(q)命令退出即可。

最终的sed编辑器脚本如下所示: $ cat data7.txt Line1 Line2 Line3 Line4 Line5 Line6 Line7 Line1 Line2 Line3 Line4 Line5 Line6 Line7 Line8 Line9 Line10 Line11 Line12 Line13 Line14 Line15 $ $ sed ‘{ > :start > $q ; N ; 11,$D > b start > }’ data7.txt Line6 Line7 Line8 Line9 Line10 Line11 Line12 Line13 Line14 Line15 $ 该脚本首先检查当前行是否为数据流中的最后一行。如果是,则退出命令会停止循环,N命令会将下一行附加到模式空间中的当前行之后。如果当前行在第10行之后,则11,$D命令会删除模式空间中的第1行。这就在模式空间中创造了滑动窗口的效果。因此,这个sed程序脚本只会显示data7.txt文件最后10行。

From #

Linux命令行与shell脚本编程大全

给文件中的行编号

Content #

用等号来显示数据流中行的行号: $ sed ‘=’ data2.txt 1 Header Line 2 First Data Line 3 Second Data Line 4 End of Data Lines $ 这多少有点儿难看,因为行号出现在了实际行的上方。更好的解决办法是将行号和文本放在同一行。

你已经知道如何用N命令合并行,在sed脚本中使用这个命令并不难。棘手之处在于,无法将两个命令放到同一个脚本中。在获得了等号命令的输出之后,可以通过管道将输出传给另一个sed编辑器脚本,由后者使用N命令来合并这两行。还需使用替换命令将换行符更换成空格或制表符。最终的解决方法如下所示: $ sed ‘=’ data2.txt | sed ‘N; s/\n/ /’ 1 Header Line 2 First Data Line 3 Second Data Line 4 End of Data Lines $ 现在看起来好多了。在查看错误消息的行号时,这是一个很好用的小工具。

有些bash shell命令也能添加行号,但是会引入一些额外的(可能是不需要的)间隔: $ nl data2.txt 1 Header Line 2 First Data Line 3 Second Data Line 4 End of Data Lines $ $ cat -n data2.txt 1 Header Line 2 First Data Line 3 Second Data Line 4 End of Data Lines $ $ nl data2.txt | sed ’s/ /; s\t/ /’ 1 Header Line 2 First Data Line 3 Second Data Line 4 End of Data Lines $ sed编辑器脚本的输出没有任何多余的间隔。但如果确实想使用这些工具,则sed 可以删除任何不需要的间隔。

...

对可能含有空行的文件加倍行间距

Content #

如果文本文件已经有一些空行,但你想给所有行加倍行间距,怎么办呢?如果沿用前面的脚本,有些区域会有太多的空行,因为已有的空行也会被加倍: $ cat data6.txt Line one. Line two.

Line three. Line four. $ $ sed ‘$!G’ data6.txt Line one.

Line two.

Line three.

Line four. $ 原来是空行的位置现在有3个空行了。

这个问题的解决办法是,首先删除数据流中的所有空行,然后用G命令在每行之后插入新的空行。要删除已有的空行,需要将d命令和一个匹配空行的模式一起使用: >/^\(/d 这个模式使用了行首锚点(^)和行尾锚点(\))。将这个模式加入脚本就能生成想要的结果: $ sed ‘/^$/d ; $!G’ data6.txt Line one.

Line two.

Line three.

Line four. $

From #

Linux命令行与shell脚本编程大全

加倍行间距

Content #

来看一个向文本文件的行间插入空行的简单sed脚本: $ sed ‘G’ data2.txt Header Line

First Data Line

Second Data Line

End of Data Lines

$ 看起来相当简单。这个技巧的关键在于保留空间的默认值。记住,G命令只是将保留空间内容附加到模式空间内容之后。当启动sed编辑器时,保留空间只有一个空行。将它附加到已有行之后,就创建出了空行。

这个脚本在数据流的最后一行(也就是文件末尾)后面也加了一个空行。如果不想要这个空行,可以用排除符号(!)和行尾符号($)来确保脚本不会将空行附加到数据流的最后一行之后: $ sed ‘$!G’ data2.txt Header Line

First Data Line

Second Data Line

End of Data Lines $

From #

Linux命令行与shell脚本编程大全

在大数中插入逗号

Content #

下面的脚本使用子模式在大数(long number)中插入逗号: $ echo “1234567” | sed ‘{ > :start > s/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/ > t start}’ 1,234,567 $ 这个脚本将匹配模式分成了两个子模式: .*[0-9] [0-9]{3} sed会在文本行中查找这两个子模式。第一个子模式是以数字结尾的任意长度的字符串。第二个子模式是3位数字(正则表达式中花括号的用法参见第20章)。如果匹配到了相应的模式,就在两者之间加一个逗号,每个子模式都通过其序号来标示。这个脚本使用测试命令来遍历这个大数,直到所有的逗号都插入完毕。

From #

Linux命令行与shell脚本编程大全

子模式反向替换

Content #

sed编辑器使用圆括号来定义替换模式中的子模式。随后使用特殊的字符组合来引用每个子模式匹配到的文本。反向引用由反斜线和数字组成。数字表明子模式的序号,第一个子模式为\1,第二个子模式为\2,以此类推。

在替换命令中使用圆括号时,必须使用转义字符,以此表明这不是普通的圆括号,而是用于划分子模式。这跟转义其他特殊字符正好相反。

来看一个在sed编辑器脚本中使用反向引用的例子: $ echo “The Guide to Programming” | > sed ' > s/\(Guide to\) Programming/\1 DevOps/' The Guide to DevOps $ 这个替换命令将Guide To放入圆括号,将其标示为一个子模式。然后使用\1来提取该子模式匹配到的文本。

如果需要用一个单词来替换一个短语,而这个单词刚好又是该短语的子串,但在子串中用到了特殊的模式字符,那么这时使用子模式会方便很多: $ echo “That furry cat is pretty.” | > sed ’s/furry \(.at\)/\1/' That cat is pretty. $ $ echo “That furry hat is pretty.” | > sed ’s/furry \(.at\)/\1/' That hat is pretty. $ 在这种情况下,不能用&符号,因为它代表的是整个模式所匹配到的文本。而反向引用则允许将某个子模式匹配到的文本作为替换内容。

当需要在两个或多个子模式间插入文本时,这个特性尤其有用。比如: 在大数中插入逗号

From #

Linux命令行与shell脚本编程大全

sed模式替换中的&符号

Content #

&符号可以代表替换命令中的匹配模式。不管模式匹配到的是什么样的文本,都可以使用&符号代表这部分内容。这样就能处理匹配模式的任何单词了: $ echo “The cat sleeps in his hat.” | > sed ’s/.at/"&"/g' The “cat” sleeps in his “hat”. $ 当模式匹配到单词cat,“cat"就会成为替换后的单词。当模式匹配到单词hat, “hat"就会成为替换后的单词。

From #

Linux命令行与shell脚本编程大全

用测试命令删除所有的逗号

Content #

用分支命令删除所有的逗号

$ echo “This, is, a, test, to, remove, commas.” | > sed -n ‘{ > :start > s/,//1p > 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. $ 当没有逗号可替换时,测试命令不再跳转,而是继续执行剩下的脚本(在本例中,也就是结束脚本)。

...