Bash 脚本将匹配模式之间的行转换为列

Bash 脚本将匹配模式之间的行转换为列

我的输入文件看起来像这样..

START
line1
line2
line3
END
START
line11
line22
line33
END

我希望我的脚本输出如下:

START line1 line2 line3 END
START line11 line22 line33 END

请帮忙。

答案1

使用awk

$ awk '{printf "%s", $0 (($0 == "END") ? ORS : OFS)}'

如果你想从STARTEND排成一行,那么可以使用以下内容:

$ awk '($0 =]"START"),($0 == "END"){printf "%s%s",$0, ($0=="END" ? ORS : OFS)}'

如果没有STARTEND可以使用以下命令:

$ awk '($0 == "START"){a="";} {a = a $0 (($0 == "END") ? "" : OFS)}  ($0 == "END"){print a}'

答案2

使用 GNU awk 进行多字符RSRT并假设您的数据始终具有完整的、非嵌套的、非重叠的 START-END 块,如示例所示:

$ awk -v RS='\nEND\n' -F'\n' '{$0=$0 RT; $1=$1} 1' file
START line1 line2 line3 END
START line11 line22 line33 END

如果您可以在 START-END 块之外添加行,请改为执行以下操作:

$ awk -v RS='\nEND\n' -F'\n' 'RT{$0=gensub(/.*\n(START\n)/,"\\1",1) RT; $1=$1; print}' file
START line1 line2 line3 END
START line11 line22 line33 END

或使用任何 awk:

$ awk '
    $0 == "START" { f=1; rec=$0; next }
    f { rec=rec OFS $0; if ( $0 == "END" ) { print rec; f=0 } }
' file
START line1 line2 line3 END
START line11 line22 line33 END

如果您可能有嵌套、重叠或不完整的 START-END 块,并且上述内容没有达到您想要的效果,那么您必须编辑您的问题以向我们展示这些要求。

答案3

使用sed

$ sed -n -e '/^START$/ { h; d; }' -e H -e '/^END$/ { g; y/\n/ /; p; }' file
START line1 line2 line3 END
START line11 line22 line33 END

sed脚本打印精美,附有注释:

# Save each "START" line in the hold space and skip to the next line.
/^START$/ {
    h
    d
}

# Append all non-"START" lines to the hold space.
H

# On an "END" line, get the hold space, convert newlines to spaces, and print.
/^END$/ {
    g
    y/\n/ /
    p
}

这假设“START”和“END”行的范围不重叠,并且“END”和“START”之间没有额外的数据。

答案4

使用(以前称为 Perl_6)

要删除一条记录与下一条记录之间的中间行(即 END和之间START):

~$ raku -ne 'S/ <!after END> $/ / andthen do if /^START/ fff s/^END$/END\n/ {.print};'  file

或者:

~$ raku -ne 'S/ <!after END> $/ / andthen print ($_ if /^START/ fff s/^END$/END\n/) ;'  file

上面是用 Raku 编程语言编码的答案。简而言之,-ne命令行标志用于在输入文件上逐行运行代码,而不自动打印。对不以单词 结尾S///的每一行(负向后查找)使用“big-S”替换运算符,添加一个空格。此步骤可以轻松地将行与中间的空格连接起来(注意:用于获得类似于 @Kusalananda 在评论中发布的答案)。<!after END> $END\t

继续,$_使用 重新加载主题变量andthen。现在您可以使用 Raku 类似 sed 的/START/ fff /STOP/“三 f”触发器运算符来捕获所需哨兵线之间的线。在格式化技巧中,您实际上可以s/^END$/END\n/替换END同一fff触发器运算符中的哨兵行,\n在 后添加换行符END

最后,输出是通过 Raku 的简单print运算符完成的,它不添加自己的换行符,保留了上面的空格/换行格式。

输入示例:

START
line1
line2
line3
END
test
START
line11
line22
line33
END

示例输出(删除中间行):

START line1 line2 line3 END
START line11 line22 line33 END

现在,如何保留中间线?很简单:只需更改触发器运算符即可使用 Raku 的“whatever-star”fff接受任何起始线。*见下文:

~$ raku -ne 'S/ <!after END> $/ / andthen do if * fff s/^END$/END\n/ {.print};'  file
START line1 line2 line3 END
test START line11 line22 line33 END

#OR

~$ raku -ne 'S/ <!after END> $/ / andthen print ($_ if * fff s/^END$/END\n/);'  file
START line1 line2 line3 END
test START line11 line22 line33 END

https://docs.raku.org/syntax/S%2F%2F%2F%20非破坏性%20替换
https://docs.raku.org/routine/fff
https://docs.raku.org/routine/andthen
https://raku.org

相关内容