使用 awk
或 sed
如何选择出现在两个不同标记模式之间的线条?可能有多个部分标有这些模式。
例如:假设文件包含:
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>
sed
或 awk
中是否有任何方法可以重复执行直到文件结束?
必要时使用带有标志的 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?。
使用 sed
:
sed -n -e '/^abc$/,/^mno$/{ /^abc$/d; /^mno$/d; p; }'
-n
选项表示默认不打印。
该模式查找仅包含 abc
到仅 mno
的行,然后执行 { ... }
中的操作。第一个动作删除 abc
行;第二个 mno
行; p
打印剩余的行。您可以根据需要放松正则表达式。 abc
..mno
范围之外的任何行都不会打印。
-e
的目的是什么
sed
应该执行的脚本的(部分)。如果您想要或需要使用多个参数来包含整个脚本,那么您必须在每个此类参数之前使用 -e
;否则,它是可选的(但明确的)。
d
应用于第一个匹配之前的所有行,然后将另一个 d
应用于从第二个匹配开始的所有行?
sed -n '1,/\\begin{document}/d;/\\end{document}/d;p'
的 LaTeX。 (这有点作弊,因为第二部分直到文档末尾都没有删除,而且我不知道如何按照 OP 的要求剪切多个部分。)
$
标记的原因是什么,如 /^abc$
和其他
这可能对您有用(GNU sed):
sed '/^abc$/,/^mno$/{//!b};d' file
删除除以 abc
和 mno
开头的行之外的所有行
!d;//d
打 2 个字符更好 :-) stackoverflow.com/a/31380266/895245
{//!b}
阻止 abc
和 mno
包含在输出中,但我不知道如何。你能解释一下吗?
//!b
读取,中断并因此打印这些行,否则将删除所有其他行。
sed '/^abc$/,/^mno$/!d;//d' file
比 ppotong's {//!b};d
更擅长打两个角色
空的正斜杠 //
表示:“重用上次使用的正则表达式”。并且该命令的作用与更容易理解的相同:
sed '/^abc$/,/^mno$/!d;/^abc$/d;/^mno$/d' file
如果一个 RE 为空(即没有指定模式),sed 的行为就像在最后一个应用的命令中使用的最后一个 RE 一样(作为地址或作为替代命令的一部分)。
从上一个响应的链接中,为我做的,在 Solaris 上运行 ksh
,是这样的:
sed '1,/firstmatch/d;/secondmatch/,$d'
1、/firstmatch/d:从第1行到第一次找到firstmatch,删除。
/secondmatch/,$d:从第一次出现 secondmatch 到文件末尾,删除。
分号分隔两个命令,按顺序执行。
1,
) 出现在 /firstmatch/
之前?我猜这也可以表述为'/firstmatch/1,d;/secondmatch,$d'
?
像这样的东西对我有用:
文件.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 解决方案比我的更好/更漂亮。
来自 Show only text between 2 matching pattern 的 Don_crissti 的回答?
firstmatch="abc"
secondmatch="cdf"
sed "/$firstmatch/,/$secondmatch/!d;//d" infile
这比 AWK 的应用程序高效得多,请参阅 here。
perl -lne 'print if((/abc/../mno/) && !(/abc/||/mno/))' your_file
我尝试使用 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
这也可以通过对标志的逻辑操作和递增/递减操作来完成:
awk '/mno/&&--f||f||/abc/&&f++' file
flag
重命名为 f
之后,本着一些好的 ol' 代码高尔夫乐趣的精神。 :-)
不定期副业成功案例分享
awk '/abc/{a=1}/mno/{print;a=0}a' file
。awk '/abc/{a=1} a; /mno/{a=0}' file
- 有了这个,将a
条件放在/mno/
之前,我们让它在设置a=0
之前评估该行为真(并打印它)。这样我们就可以避免写print
。awk '/abc/,/mno/' file
awk 'flag; /PAT1/{flag=1; next} /PAT1/{flag=0}' file
会成功。[pattern] { action }
或pattern [{ action }]
。 2. 一个动作由一个或多个 awk 语句组成,括在大括号 ('{...}') 中。 —— 所以结尾的flag
是flag {print $0}
的缩写