使用sed获取包含正则表达式的所有行并附加到文件末尾

时间:2016-02-10 00:22:22

标签: sed

我正在尝试使用sed脚本来获取包含模式的所有行并将它们移动到输出的末尾。这是一个学习保持与模式空间的练习,我正在努力想出它(尽管我感觉很接近)。

我在这里:

$ echo -e "hi\nfoo1\nbar\nsomething\nfoo2\nyo" | sed -E '/foo/H; //d; $G'
hi
bar
something
yo

foo1
foo2

但我希望输出为:

hi
bar
something
yo
foo1
foo2

我明白为什么会这样。这是因为我们第一次发现foo保持空间是空的,所以H将\n附加到空白保留空间,然后是第一个foo,我认为这很好。但是然后$ G再次执行它,即另一个附加追加\n加上保留空间中的内容到模式空间。

我尝试了/^$/d的最终删除命令,但没有删除空白行(我认为这是因为这个模式不是与最后一行匹配,而是与现在的多行模式空间相匹配其中有\n\n

我确信sed大师对我有解决方法。

3 个答案:

答案 0 :(得分:1)

这可能适合你(GNU sed):

sed '/foo/H;//!p;$!d;x;//s/.//p;d' file

如果该行包含所需的字符串,则将其附加到保留空间(HS),否则将其正常打印。如果不是最后一行,则删除它,否则将HS替换为模式空间(PS)。如果所需的字符串现在在PS中(什么是HS);因为附加了所有这些模式,所以第一个字符将是换行符,删除第一个字符并打印。删除剩下的东西。

另一种方法,使用-n标志:

sed -n '/foo/H;//!p;$!b;x;//s/.//p' file

N.B。当执行db(没有参数)命令时,没有其他sed命令,新行被读入PS,sed脚本以第一个命令开始,即sed命令不继上一个d命令后继续。

答案 1 :(得分:1)

为什么呢?这样的东西在awk中绝对是微不足道的,awk在sed的每个地方都可用,并且生成的awk脚本将比sed脚本执行相同的任务几乎所有其他方式更简单,更便携,更快速和更好。在20世纪70年代中期发明awk之前,所有持有太空物品的东西都是必需的,但除了作为一种心理锻炼之外,它现在绝对没有用。

$ echo -e "hi\nfoo1\nbar\nsomething\nfoo2\nyo" |
    awk '/foo/{buf = buf $0 RS;next} {print} END{printf "%s",buf}'
hi
bar
something
yo
foo1
foo2

以上内容将在每个UNIX安装的每个awk中按原样运行,我打赌你可以很容易地弄清楚它是如何工作的。

答案 2 :(得分:0)

这感觉就像一个黑客,我认为应该可以更优雅地处理这种情况。以下适用于GNU sed

echo -e "hi\nfoo1\nbar\nsomething\nfoo2\nyo" | sed -r '/foo/{H;d;}; $G; s/\n\n/\n/g'

但是,在OSX / BSD sed上,会产生奇数输出:

hi
bar
something
yonfoo1
foo2

请注意,2个连续的换行符已替换为文字字符n

解释了OSX / BSD与GNU sed in this article。以下工作(在GNU SED中也是如此):

echo -e "hi\nfoo1\nbar\nsomething\nfoo2\nyo" | sed '/foo/{H;d;}; $G; s/\n\n/\'$'\n''/' 

TL; DR;在BSD sed中,它不接受替换表达式的RHS中的转义字符,所以你要么必须在命令行放置一个真正的LF /换行符,要么在上面你需要将sed脚本字符串拆分到你需要的地方RHS的换行符并在' \ n'前面加上一个美元符号。所以shell interprets it as a line feed