我需要从文件中删除在pattern1之后和在模式2和pattern3 之间的行,如下所示:
aaaaaaaa
bbbbbbbb
pattern1 <-----After this line
cdededed
ddededed
pattern2
fefefefe <-----Delete this line
efefefef <-----Delete this line
pattern3
adsffdsd
huaserew
请您建议如何使用awk或sed或perl来完成此操作。
答案 0 :(得分:4)
sed '/pattern1/,${ /pattern2/,/pattern3/{/pattern2/b; /pattern3/b; d;} };' file
格式化:
/pattern1/,$ {
/pattern2/,/pattern3/ {
/pattern2/b;
/pattern3/b;
d;
}
}
说明:
/pattern1/,$
是pattern1
之后到文件末尾的行数范围/pattern2/,/pattern3/
是pattern2
和pattern3
/pattern2/b;
和/pattern3/b;
会跳过范围内包含的pattern2
和pattern3
行(请参阅the sed faq)d
删除范围<强>更新强>
从评论中,可以重写内部块:
//!d
其中:
//
(空模式)与最后使用的正则表达式匹配(在本例中为pattern2
和pattern3
!
反转下一个命令,使其适用于除匹配模式的行以外的所有 d
删除这些行所以完整的重写模式是:
/pattern1/,$ {
/pattern2/,/pattern3/ {
//!d
}
}
答案 1 :(得分:3)
像状态机一样使用awk:
awk '
BEGIN {print_line = 1}
/pattern1/ {consider = 1}
consider && /pattern2/ {print_line = 0; print}
consider && /pattern3/ {print_line = 1}
print_line {print}
' filename
答案 2 :(得分:2)
如果您正在使用perl在命令行上寻找快速解决方案,这是flip-flop
运算符的理想情况。现在,有两种方法可以在边缘情况下解释这个问题 - 只要pattern1
出现在pattern2
之前,这两种方法的功能都相同:
如果 pattern1 位于 pattern2 之后,但在 pattern3 之前删除 pattern1 和 pattern3 强>
或者,如果 pattern1 位于 pattern2 之后,但 pattern3 之前不执行任何操作,除非您看到另一个的模式1 强>
在开始之前,请注意perl争论-p
-n assume "while (<>) { ... }" loop around program
-p assume loop like -n but print line also, like sed
现在,首先,我给你了..
perl -pe'$x ||= /7/; $_= "" if /5/ .. /8/ and $x' <(seq 1 10)
1
2
3
4
5
6
9
10
$x ||= /7/
:当$x
为/7/
时,这会将$x
设置为false
的返回值。 /7/
匹配时会返回true
。这意味着$x
在第一次匹配时设置为true,||=
的性质永远不会在变量已经为真时设置。
如果范围介于$_ = ''
和/5/
之间并且已将/8/
设置为true,则会设置$x
。请记住短路的工作方式:a && b
表示仅当b
评估为a
时才会运行true
。在这种情况下,仅仅评估a
的事实将设置触发器操作符的状态 - 这就是我们想要的;但是,如果已经看到$_ = ''
,我们只希望7
出现。
现在,对问题的第二种解释只是切换顺序......
perl -pe'$x ||= /7/; $_= "" if $x and /5/ .. /8/' <(seq 1 10)
这将打印全范围。 Perl在找到/5/
之后才会开始寻找/7/
。在我们不会发生的顺序范围内。
perl -pe'$x||=/2/;$_=""if$x&&/5/../8/' # secksey
答案 3 :(得分:1)
完成Rosetta Stone:
perl -ne '++$saw_pattern1 if /pattern1/;
$inside = ($saw_pattern1 && /pattern2/) .. /pattern3/;
print unless $inside && ($inside > 1 && $inside !~ /E0$/)' \
input
代码利用了Perl的..
range operator。
在标量上下文中,
..
返回一个布尔值。运算符是双稳态的,如触发器,并模拟 sed , awk 和各种编辑器的行范围(逗号)运算符。每个..
运算符都维护自己的布尔状态,甚至在调用包含它的子例程时也是如此。只要其左操作数为假,它就是假的。一旦左操作数为真,范围运算符将保持为真,直到右操作数为真, AFTER ,范围运算符再次变为假。在下次评估范围运算符之前,它不会变为错误...当操作符处于false状态时,不评估右操作数,并且在操作符处于true状态时不评估左操作数。优先级略低于
||
和&&
。返回的值是false的空字符串,或者是true的序列号(以1开头)。为遇到的每个范围重置序列号。范围中的最终序列号附加了字符串E0
,它不会影响其数值,但如果要排除端点,则可以搜索。您可以通过等待序列号大于1来排除起始点。
答案 4 :(得分:1)
这可能对您有用:
sed '/pattern1/,$!b;/pattern2/,/pattern3/!b;//!d' file