![Bash 脚本将匹配模式之间的行转换为列](https://linux22.com/image/225684/Bash%20%E8%84%9A%E6%9C%AC%E5%B0%86%E5%8C%B9%E9%85%8D%E6%A8%A1%E5%BC%8F%E4%B9%8B%E9%97%B4%E7%9A%84%E8%A1%8C%E8%BD%AC%E6%8D%A2%E4%B8%BA%E5%88%97.png)
我的输入文件看起来像这样..
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)}'
如果你想从START
到END
排成一行,那么可以使用以下内容:
$ awk '($0 =]"START"),($0 == "END"){printf "%s%s",$0, ($0=="END" ? ORS : OFS)}'
如果没有START
则END
可以使用以下命令:
$ awk '($0 == "START"){a="";} {a = a $0 (($0 == "END") ? "" : OFS)} ($0 == "END"){print a}'
答案2
使用 GNU awk 进行多字符RS
,RT
并假设您的数据始终具有完整的、非嵌套的、非重叠的 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