2015-10-14 38 views

回答

3

您可以使用一个简单的状态机awk,如与下面的输入文件,稍加修改中,也允许文本标记(如果没有这样的文本,它会仍然工作的需要,这只是处理额外箱子):

xyzzy 
plugh 
<INFOSTART 
A=1 
B=2 
C=3 
D=4 
<INFOEND 
twisty 
passages 
<INFOSTART 
G=1 
Z=3 
<INFOEND 
after 
last 

有了这样的(或原始的数据文件),以下awk命令给你你需要什么,开始之间的结合线和结束标记合并为一行:

awk ' /^<INFOSTART$/ {inside=1; sep=""; next} 
     /^<INFOEND$/ {inside=0; print ""; next} 
     inside   {printf sep""$0; sep=" "; next} 
        {print}' input_file 

xyzzy 
plugh 
A=1 B=2 C=3 D=4 
twisty 
passages 
G=1 Z=3 
after 
last 

更详细地检查awk代码,以下各节将在每行中进行扩展。


只要找到仅包含开始标记的行,就会运行以下段。它将inside状态设置为true(非零)以指示您应该开始合并行,并将初始分隔符设置为空字符串以确保组合行上没有前导空格。该next只是去,并立即抓住下一个输入线,开始一个新的循环:

/^<INFOSTART$/ {inside=1; sep=""; next} 

假设你没有找到一个开始标记,该片段进行结束标志运行。如果找到,则inside状态将重置为false(零),以开始输出与输入文件中显示的行完全相同的行。它还输出一个换行符妥善完成合并行,然后重新启动下一个输入线周期:

/^<INFOEND$/ {inside=0; print ""; next} 

如果您已经确定行既不是开始也不是结束标志,你的行为取决于inside状态。为了实现这一点,您需要将输入行组合到一个输出行中,因此只需简单地打印即可,而不会在尾随换行符处打印分隔符,然后是行本身。然后,将分隔符设置为一个空格,以便下一个输入行将与前一行正确分隔。然后,它循环回到下一个输入行:

inside   {printf sep""$0; sep=" "; next} 

最后,如果你来到这里,你知道你是一个开始/结束部分之外,所以你只是呼应,正是因为它存在于行输入文件:

   {print}' 

如果您不想格式良好的版本,你可以使用下面的缩小的版本,假设你是某只<INFO...线的开始和结束标记:

awk '/^<INFOS/{a=1;b="";next}/^<INFOE/{a=0;print"";next}a{printf b$0;b=" ";next}1' 

但是,由于这可能是一个脚本而不是单行命令,我倾向于坚持使用可读的版本。

+0

工作一个魅力感谢状.. –

1

Perl来救援:

< input perl -ne 's/\n/ /, print if $s = /<INFOSTART/ .. ($e = /<INFOEND/) 
            and $s > 1 and !$e; 
        print "\n" if $e' 

$ S当我们的标签(使用..运营商)之间的是真实的。如果我们匹配结束标记,则$ e为真,当匹配开始标记时,$ s为1。

+0

当然,这不是Perl中,我实际上可以读它:-) – paxdiablo

3

随着trsed

AMD$ tr '\n' ' ' < File | sed 's/<INFOSTART //g; s/<INFOEND /\n/g' 
A=1 B=2 C=3 D=4 
G=1 Z=3 

替换所有newlinesspace第一。然后使用sed删除所有<INFOSTART并用newlines替换全部<INFOEND

+0

didnt想想那.. ..谢谢 –

1

这可能为你工作(GNU SED):

sed '/^<INFOSTART/d;:a;N;/^<INFOEND/M!s/\n/ /;ta;P;d' file 

这将删除开始<INFOSTART<INFOEND线,用空格替换所有其他行之间的换行符。

该解决方案可以削减进一步下降(提供文件很好地形成)到:

sed '/^</d;:a;N;/^</M!s/\n/ /;ta;P;d' file 
相关问题