我正在尝试使用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
大师对我有解决方法。
答案 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。当执行d
或b
(没有参数)命令时,没有其他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。