提取 2 个图案之间(包括 2 个图案)之间的线条

提取 2 个图案之间(包括 2 个图案)之间的线条

我有一个数据结构如下的文件

1, p1, p2, p3, p4, p5, p6, p7
2, p9, p10,,
2, q1, q2, q3, q4, q5, q6, q7
2, q9, q10,,
2, r1, r2, r3, r4, r5, r6, r7
2, r9, r10,,
1, s1, s2, s3, s4, s5, s6, s7
2, s9, s10,,
...

我想要得到所有以 1 开头并以 , 结尾的行,这样我就得到

1, p1, p2, p3, p4, p5, p6, p7
2, p9, p10,,
1, s1, s2, s3, s4, s5, s6, s7
2, s9, s10,,

如果可能的话,

1, p1, p2, p3, p4, p5, p6, p7, 2, p9, p10,,
1, s1, s2, s3, s4, s5, s6, s7, 2, s9, s10,,

我怎样才能用 sed 或 awk 来做到这一点?

答案1

这是一个解决方案,它将最后出现的行之后的任意行sed序列串在一起:,,$^1

sed -e '/^1/{x;s/\n/ /gp;d' -e '};/,,$/H;$G;D
' <<\IN                                                                          
1, p1, p2, p3, p4, p5, p6, p7
2, p9, p10,,
2, q1, q2, q3, q4, q5, q6, q7
2, q9, q10,,
2, r1, r2, r3, r4, r5, r6, r7
2, r9, r10,,
1, s1, s2, s3, s4, s5, s6, s7
2, s9, s10,,
IN

x会更改h以 a 开头的行上的旧空间和模式空间^1,并且仅在成功替换的情况下才会s///p打印旧空间之前的内容。h以 结尾的行将,,$附加到ewline 字符H后面的旧空格\n,然后所有行都会被D删除,直到第一个出现的\newline 字符。在$最后一行,H旧空格被附加到\newline 后面的模式空间中 - 因此当它被D删除时,它会在脚本顶部重新启动仅包含旧H空格所包含内容的行循环 - 这会根据需要打印它。

输出:

1, p1, p2, p3, p4, p5, p6, p7 2, p9, p10,, 2, q9, q10,, 2, r9, r10,,
1, s1, s2, s3, s4, s5, s6, s7 2, s9, s10,,

另一方面,如果您不希望后续发生这种/,,$/情况,则可以这样做:

sed -e '/^1/{x;y/\n/ /;s/,,.*/,,/p;d' -e '};/,,$/H;$G;D'

给定打印的相同输入:

1, p1, p2, p3, p4, p5, p6, p7 2, p9, p10,,
1, s1, s2, s3, s4, s5, s6, s7 2, s9, s10,,

但是,/,,$/即使它们没有立即跟随/^1/匹配,也会打印出行。如果您只需要这些对在输入中立即连续,您也可以这样做:

sed -n '/^1/!d;$p;N;/\n1/P;/,,$/s/\n/ /p;D'

其工作原理如下:

  • 它首先d从输出中删除所有不!/^1/
    • 这包括引入但N不以 结尾的行/,,$/
  • 如果这是$最后一个输入行,则在此处打印模式空间p,因为下一个命令将结束脚本。
  • /^1/匹配时,它将Next 输入行附加到模式空间中的\newline 字符后面。
  • 如果附加行以 a 开头,/\n1/P会打印前一个。
    • P仅打印\n模式空间中第一个出现的 ewline。
  • 拉入Next 输入行后,如果模式空间$以匹配结尾/,,$/,它将s///用空格字符替换插入的\newline 字符并p打印结果。
  • 模式空间为总是 D删除直到并包括第一个出现的\newline 字符。
    • ...因此,当Next 输入行不匹配时/,,$/,它会作为行首发送回脚本顶部。如果此时不匹配,^1则会d完全删除。
    • ...因为此时/,,$/已经完全删除了它们的ewline,因此它们在这里完全从流程中删除。\n

所有这些都意味着,如果/^1/行彼此相连,它们仍然会被打印,如果行不以,,$a结尾^1,它们就不会被打印。

答案2

关于您的第一个查询,您可以使用-esed 中的组合表达式:

~$ sed -n -e '/^1/p' -e '/,,$/p' f
1, p1, p2, p3, p4, p5, p6, p7
2, p9, p10,,
2, p9, p10,,
2, p9, p10,,
1, p1, p2, p3, p4, p5, p6, p7
2, p9, p10,,

如果你不想要重复的:

~$ sed -n -e '/^1/p' -e '/,,$/p' f | uniq
1, p1, p2, p3, p4, p5, p6, p7
2, p9, p10,,
1, p1, p2, p3, p4, p5, p6, p7
2, p9, p10,,

使用 awk,将正则表达式与;

~$ awk '/^1/;/,,$/' f
1, p1, p2, p3, p4, p5, p6, p7
2, p9, p10,,
2, p9, p10,,
2, p9, p10,,
1, p1, p2, p3, p4, p5, p6, p7
2, p9, p10,,

答案3

您可以有条件地设置ORS以获得所需格式的输出

awk '/^1/,/,,$/{ORS = /^1/? ", ": "\n"; print}' file
1, p1, p2, p3, p4, p5, p6, p7, 2, p9, p10,,
1, p1, p2, p3, p4, p5, p6, p7, 2, p9, p10,,

相关内容