Content #
数据文件开头有多个空行也很烦人。将数据从文本文件中导入数据库时,空行会产生一些空项,涉及这些数据的计算都无效。
删除数据流起始处的空行不难。下面是实现该功能的脚本:
/./,$!d
这个脚本用地址区间来决定要删除哪些行。这个区间从含有字符的行开始,一直到数据流结束。在这个区间内的任何行都不会从输出中删除。这意味着含有字符的第一行之前的任何行都会被删除。
From #
Linux命令行与shell脚本编程大全
如何用美元符号来显示数据流末尾的若干行呢?答案是创建滚动窗口(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行。
Linux命令行与shell脚本编程大全
用等号来显示数据流中行的行号: $ 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 可以删除任何不需要的间隔。
...如果文本文件已经有一些空行,但你想给所有行加倍行间距,怎么办呢?如果沿用前面的脚本,有些区域会有太多的空行,因为已有的空行也会被加倍: $ 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. $
Linux命令行与shell脚本编程大全
来看一个向文本文件的行间插入空行的简单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 $
Linux命令行与shell脚本编程大全
下面的脚本使用子模式在大数(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章)。如果匹配到了相应的模式,就在两者之间加一个逗号,每个子模式都通过其序号来标示。这个脚本使用测试命令来遍历这个大数,直到所有的逗号都插入完毕。
Linux命令行与shell脚本编程大全
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. $ 在这种情况下,不能用&符号,因为它代表的是整个模式所匹配到的文本。而反向引用则允许将某个子模式匹配到的文本作为替换内容。
当需要在两个或多个子模式间插入文本时,这个特性尤其有用。比如: 在大数中插入逗号
Linux命令行与shell脚本编程大全
$ 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. $ 当没有逗号可替换时,测试命令不再跳转,而是继续执行剩下的脚本(在本例中,也就是结束脚本)。
...