![如何打印多次出现的同一图案之间的线条?](https://linux22.com/image/111746/%E5%A6%82%E4%BD%95%E6%89%93%E5%8D%B0%E5%A4%9A%E6%AC%A1%E5%87%BA%E7%8E%B0%E7%9A%84%E5%90%8C%E4%B8%80%E5%9B%BE%E6%A1%88%E4%B9%8B%E9%97%B4%E7%9A%84%E7%BA%BF%E6%9D%A1%EF%BC%9F.png)
需要提取与指定的搜索模式出现次数相同的模式之间的行
就像我想获取搜索模式第一次和第二次出现之间的行或第三次和第四次出现之间的行一样。模式之间可能没有任何行,如果模式之间没有行,则输出应该为空白
例子: -
Line 1
Line 2
Line 3
Pattern
Line 5
Line 6
Line 7
Pattern
Line 8
Line 9
Pattern
Line 11
Line 12
Pattern
Line 13
Pattern
Pattern
第一次和第二次出现之间的预期输出行
Line 5
Line 6
Line 7
第三次和第四次出现之间的行
Line 11
Line 12
答案1
基于这个答案,
awk '/Pattern/{n+=1}; n % 2 == 1 && ! /Pattern/ {print > "output"((n-1)/2)}' input_file
解释
/Pattern/{n+=1}
:匹配时Pattern
,加n
1。n % 2 == 1 && ! /Pattern/
:仅在 n 为奇数时(即在每个替代模式之后)执行以下操作。另外,请忽略Pattern
上面带有 的线条。{print > "output"((n+1)/2)}'
:如果上述成立,则将该行打印到名为 的文件中outputx
,其中x
是((n+1)/2)
,即output1
,output2
,output3
...
答案2
替代 AWK 方法
$ awk -v start=3 '/Pattern/{n++;next};n==start;n==start+1{exit}' input.txt
Line 11
Line 12
$ awk -v start=2 '/Pattern/{n++;next};n==start;n==start+1{exit}' input.txt
Line 8
Line 9
解释
其工作方式相当简单:
- 使用
-v
标志我们定义一个变量,如果我们找到匹配的模式并转到下一行(这是/Pattern/{n++;next}
代码的一部分),我们就会增加该变量 - 在 awk 中,如果条件为 true,则自动生成打印内容的信号,因此
n==start
可以视为与 相同n==start{print}
。 - 最后的代码块,我们查看是否到达下一个模式是
n==start+1
{exit}. Say we wanted to print lines between 4th and 5th pattern occurrence. This will mean that when
n==4+1` 代码退出
如果我们正在进行代码高尔夫,我们可以通过将start
变量更改为类似的东西来-v s=1
缩短代码,如下所示:
awk -v s=3 '/Pattern/{n++;next};n==s;n==s+1{exit}'
假设:
- GNU awk
- 我们正在连续模式之间读取,即在 match
n
和n+1
概括该方法
如果我们想打印图案 2 到图案 4 之间的线条怎么办?使用前面示例中使用的一些技巧,我们也可以这样做:
$ awk -v start=2 -v finish=4 '/Pattern/{n++;next};n==finish{exit};n>=start' input.txt
Line 8
Line 9
Line 11
Line 12
请注意,这里我们定义了另一个变量 ,finish
来知道在哪里停止。这样n==finish
将停止打印线条。还要注意,它n==finish{exit}
出现在 之前n>=start
,这使我们能够避免在应该退出的同一行上进行多余的打印。
答案3
和sed
:
sed -n '/Pattern/!d;:a
n;//! {w file1.txt
ba
};:b
n;//! bb
:c
n;//q;w file2.txt
bc
' file
对于 POSIX,sed
您必须为匹配项和中间项执行 3 个这样的循环,因为您无法从脚本内生成文件名。
答案4
start=3; # these can only be positive integers
stop=4; # stop > start
perl -lne "// or print if /Pattern/ && ++\$a == $start ... // && ++\$a == $stop" data.in
Perl 解决方案使用范围运算符...
,其中两个操作数的作用类似于触发器: => 只要第一个操作数为 false,...就返回 false。一旦第一个操作数为真,... 就返回真。仅当第二个操作数变为 true 时,它才会变为 false。之所以出现这种微妙之处,是因为操作数 1 一旦为真就不会被求值,而操作数 2 在操作数 1 为假时也不会被求值。
sed -nE "
/Pattern/!d
x
s/\$/./
/^[.]{$start}\$/!{x;d;}
x
n
:loop
p;n
/Pattern/{
x
s/\$/./
/^.{$stop}\$/q
x
}
bloop
" data.in
sed 解决方案使用保留空间来记录模式出现的次数。只要未看到 $start 数量的模式,我们就会一直拒绝行。一旦第 $start-th 模式到达,我们就会进入一个循环,不断读取下一行,打印它,同时测量是否看到第 $stop-th 模式。我们一看到,就赶紧退出。