ChatGPT解决这个技术问题 Extra ChatGPT

如何选择可能使用 awk/sed 多次出现的两个标记模式之间的线

使用 awksed 如何选择出现在两个不同标记模式之间的线条?可能有多个部分标有这些模式。

例如:假设文件包含:

abc
def1
ghi1
jkl1
mno
abc
def2
ghi2
jkl2
mno
pqr
stu

并且开始模式是 abc 和结束模式是 mno 所以,我需要输出为:

def1
ghi1
jkl1
def2
ghi2
jkl2

我正在使用 sed 匹配模式一次:

sed -e '1,/abc/d' -e '/mno/,$d' <FILE>

sedawk 中是否有任何方法可以重复执行直到文件结束?


C
Community

必要时使用带有标志的 awk 来触发打印:

$ awk '/abc/{flag=1;next}/mno/{flag=0}flag' file
def1
ghi1
jkl1
def2
ghi2
jkl2

这是如何运作的?

/abc/ 匹配具有此文本的行,以及 /mno/ 匹配。

/abc/{flag=1;next} 在找到文本 abc 时设置标志。然后,它跳过该行。

/mno/{flag=0} 在找到文本 mno 时取消设置标志。

最后一个标志是具有默认操作的模式,即打印 $0:如果标志等于 1,则打印该行。

有关更详细的描述和示例,以及显示或不显示模式的情况,请参阅 How to select lines between two patterns?


如果要打印模式之间的所有内容,包括,则可以使用 awk '/abc/{a=1}/mno/{print;a=0}a' file
是的,@scai!甚至 awk '/abc/{a=1} a; /mno/{a=0}' file - 有了这个,将 a 条件放在 /mno/ 之前,我们让它在设置 a=0 之前评估该行为真(并打印它)。这样我们就可以避免写 print
@scai @fedorqui 要包含模式输出,您可以执行 awk '/abc/,/mno/' file
@EirNym 这是一个奇怪的场景,可以用非常不同的方式处理:你想打印哪些行?可能 awk 'flag; /PAT1/{flag=1; next} /PAT1/{flag=0}' file 会成功。
对于像我这样的新手,有一个 doc。 1. 一个 awk “规则”包含一个“模式”和一个“动作”,其中任何一个(但不能同时省略)都可以省略。所以 [pattern] { action }pattern [{ action }]。 2. 一个动作由一个或多个 awk 语句组成,括在大括号 ('{...}') 中。 —— 所以结尾的 flagflag {print $0} 的缩写
J
Jonathan Leffler

使用 sed

sed -n -e '/^abc$/,/^mno$/{ /^abc$/d; /^mno$/d; p; }'

-n 选项表示默认不打印。

该模式查找仅包含 abc 到仅 mno 的行,然后执行 { ... } 中的操作。第一个动作删除 abc 行;第二个 mno 行; p 打印剩余的行。您可以根据需要放松正则表达式。 abc..mno 范围之外的任何行都不会打印。


@JonathanLeffler 我可以知道使用 -e 的目的是什么
@KasunSiyambalapitiya:主要是这意味着我喜欢使用它。形式上,它指定下一个参数是 sed 应该执行的脚本的(部分)。如果您想要或需要使用多个参数来包含整个脚本,那么您必须在每个此类参数之前使用 -e;否则,它是可选的(但明确的)。
好的! (我更喜欢 sed 而不是 awk。)使用复杂的正则表达式时,不必重复它们会很好。是否可以删除“选定”范围的第一行/最后一行?还是先将 d 应用于第一个匹配之前的所有行,然后将另一个 d 应用于从第二个匹配开始的所有行?
(回复我自己的评论。)如果只有一个部分要剪掉,我可以暂时解决这个问题,例如使用 sed -n '1,/\\begin{document}/d;/\\end{document}/d;p' 的 LaTeX。 (这有点作弊,因为第二部分直到文档末尾都没有删除,而且我不知道如何按照 OP 的要求剪切多个部分。)
@JonathanLeffler 插入 $ 标记的原因是什么,如 /^abc$ 和其他
p
potong

这可能对您有用(GNU sed):

sed '/^abc$/,/^mno$/{//!b};d' file

删除除以 abcmno 开头的行之外的所有行


!d;//d 打 2 个字符更好 :-) stackoverflow.com/a/31380266/895245
这太棒了。 {//!b} 阻止 abcmno 包含在输出中,但我不知道如何。你能解释一下吗?
@Brendan 如果当前行不是与范围匹配的行之一,则指令 //!b 读取,中断并因此打印这些行,否则将删除所有其他行。
C
Community
sed '/^abc$/,/^mno$/!d;//d' file

ppotong's {//!b};d 更擅长打两个角色

空的正斜杠 // 表示:“重用上次使用的正则表达式”。并且该命令的作用与更容易理解的相同:

sed '/^abc$/,/^mno$/!d;/^abc$/d;/^mno$/d' file

这个seems to be POSIX

如果一个 RE 为空(即没有指定模式),sed 的行为就像在最后一个应用的命令中使用的最后一个 RE 一样(作为地址或作为替代命令的一部分)。


我认为第二个解决方案最终将一无所获,因为第二个命令也是一个范围。不过先赞一下。
@potong 真的!我必须更多地研究为什么第一个有效。谢谢!
I
Irfan Latif

从上一个响应的链接中,为我做的,在 Solaris 上运行 ksh,是这样的:

sed '1,/firstmatch/d;/secondmatch/,$d'

1、/firstmatch/d:从第1行到第一次找到firstmatch,删除。

/secondmatch/,$d:从第一次出现 secondmatch 到文件末尾,删除。

分号分隔两个命令,按顺序执行。


只是好奇,为什么范围限制器 (1,) 出现在 /firstmatch/ 之前?我猜这也可以表述为'/firstmatch/1,d;/secondmatch,$d'
使用 "1,/firstmatch/d" 表示“从第 1 行到第一次找到 'firstmatch',删除”。而对于“/secondmatch/,$d”,您会说“从第一次出现 'secondmatch' 到文件末尾,删除”。分号分隔两个命令,它们是按顺序执行的。
p
pataluc

像这样的东西对我有用:

文件.awk:

BEGIN {
    record=0
}

/^abc$/ {
    record=1
}

/^mno$/ {
    record=0;
    print "s="s;
    s=""
}

!/^abc|mno$/ {
    if (record==1) {
        s = s"\n"$0
    }   
}

使用:awk -f file.awk data...

编辑:O_o fedorqui 解决方案比我的更好/更漂亮。


在 GNU awk 中,if (record=1) 应该是 if (record==1),即双 = - 请参阅 gawk comparison operators
2
2 revs

来自 Show only text between 2 matching pattern 的 Don_crissti 的回答?

firstmatch="abc"
secondmatch="cdf"
sed "/$firstmatch/,/$secondmatch/!d;//d" infile

这比 AWK 的应用程序高效得多,请参阅 here


我认为在这里将时间比较联系起来没有多大意义,因为问题的要求完全不同,因此解决方案也不同。
我不同意,因为我们应该有一些标准来比较答案。只有少数有 SED 应用程序。
V
Vijay
perl -lne 'print if((/abc/../mno/) && !(/abc/||/mno/))' your_file

很高兴知道 perl 等价物,因为它是 awk 和 sed 的一个很好的替代品。
W
Weekend

我尝试使用 awk 打印两个模式之间的线条,而 pattern2 也匹配 pattern1。并且 pattern1 线也应该被打印出来。

例如来源

package AAA
aaa
bbb
ccc
package BBB
ddd
eee
package CCC
fff
ggg
hhh
iii
package DDD
jjj

应该有一个输出

package BBB
ddd
eee

其中 pattern1 是 package BBB,pattern2 是 package \w*。请注意,CCC 不是已知值,因此无法逐字匹配。

在这种情况下,@scai 的 awk '/abc/{a=1}/mno/{print;a=0}a' file 和 @fedorqui 的 awk '/abc/{a=1} a; /mno/{a=0}' file 都不适合我。

最后,我设法通过awk '/package BBB/{flag=1;print;next}/package \w*/{flag=0}flag' file解决了它,哈哈

awk '/package BBB/{flag=1;print;next}flag;/package \w*/{flag=0}' file 中付出更多的努力,也打印 pattern2 行,即

package BBB
ddd
eee
package CCC

b
blhsing

这也可以通过对标志的逻辑操作和递增/递减操作来完成:

awk '/mno/&&--f||f||/abc/&&f++' file

我绝对确定我过去曾使用过 awk 来解决这个问题,而且它没有这么复杂。
显然,awk 中接受的答案比我的答案早了 7 年多,更具可读性,我在发布我的答案之前就看到了这个答案。我只是把这个扔在这里,因为它比接受的答案短一个字节,即使在将其变量 flag 重命名为 f 之后,本着一些好的 ol' 代码高尔夫乐趣的精神。 :-)