在大多数情况下,这样做可能会更好,但以防万一文件真的很大,而您又无法sed
处理那么大的脚本文件(可能会在大约5000行脚本中发生),这就是平原sed
:
sed -ne:t -e"/\n.*$match/D" \
-e'$!N;//D;/'"$match/{" \
-e"s/\n/&/$A;t" \
-e'$q;bt' -e\} \
-e's/\n/&/'"$B;tP" \
-e'$!bt' -e:P -e'P;D'
这是所谓的输入滑动窗口的示例。在尝试打印任何内容之前,它会通过建立-count行的超前缓冲区$B
来工作。
实际上,也许我应该澄清一下我的观点:该解决方案和不适用解决方案的主要性能限制因素将与间隔直接相关。此解决方案将以较大的间隔大小变慢,而do's将以较大的间隔频率变慢。换句话说,即使输入文件很大,如果实际间隔出现的次数仍然很少,那么他的解决方案可能就是解决之道。但是,如果间隔大小相对可控,并且很可能经常发生,那么这是您应该选择的解决方案。
所以这是工作流程:
- 如果
$match
在模式空间中发现前一条\n
ewline,sed
则会递归地D
删除\n
它之前的每条ewline。
- 我
$match
之前完全清除了模式空间-但要轻松处理重叠,留下一个界标似乎更好。
- 我也尝试过一口气
s/.*\n.*\($match\)/\1/
躲过循环,但是当循环$A/$B
变大时,D
elete循环的速度要快得多。
- 然后,我们在
N
输入的前一行加上\n
ewline分隔符,然后再次尝试通过引用我们最近使用的正则表达式w / 再次D
删除/\n.*$match/
一次//
。
- 如果模式空间匹配
$match
,则只能$match
在行的开头进行此操作- $B
清除所有之前的行。
- 因此,我们开始循环
$A
。
- 这个循环的每次运行,我们会尝试
s///
ubstitute为&
自己的$A
个\n
中模式空间ewline的性格,如果成功,t
EST将转移我们-我们整个$A
压脚提升缓冲-出剧本完全超过从顶部开始的脚本与下一个输入行(如果有)。
- 如果
t
est不成功,我们将b
退回到:t
op标签并递归输入另一行-如果$match
在收集$A
fter 时发生循环,则可能会开始循环。
- 如果我们闯过一个
$match
函数循环,那么我们会尽量p
RINT的$
最后一行,如果这是它,如果!
不尝试s///
ubstitute为&
自己的$B
个\n
中模式空间ewline字符。
- 我们也会对此进行
t
评估,如果成功的话,我们将转到:P
rint标签。
- 如果没有,我们将跳转回
:t
op并将另一行输入追加到缓冲区。
- 如果我们要进行
:P
rint,我们将进行P
rint,然后选出模式空间中D
的第一个\n
ewline,然后从顶部重新运行剩下的脚本。
所以这次,如果我们正在做 A=2 B=2 match=5; seq 5 | sed...
:P
Rint 的第一次迭代的模式空间如下所示:
^1\n2\n3$
这就是sed
收集其$B
efore缓冲区的方式。因此sed
,在已收集的输入后面打印以输出$B
-count行。这意味着,在我们之前的示例中,将反复打印输出,然后将其删除并将一个模式空间发送回脚本顶部,如下所示:sed
P
1
D
^2\n3$
...并且在脚本顶部N
检索ext输入行,因此下一次迭代如下所示:
^2\n3\n4$
因此,当我们找到5
输入中的第一个匹配项时,模式空间实际上看起来像:
^3\n4\n5$
然后D
elete循环开始,它通过时看起来像:
^5$
当N
扩展输入线被拉动时,sed
EOF退出。到那时,它只P
清洗了第1行和第2行。
这是一个示例运行:
A=8 B=7 match='[24689]0'
seq 100 |
sed -ne:t -e"/\n.*$match/D" \
-e'$!N;//D;/'"$match/{" \
-e"s/\n/&/$A;t" \
-e'$q;bt' -e\} \
-e's/\n/&/'"$B;tP" \
-e'$!bt' -e:P -e'P;D'
打印:
1
2
3
4
5
6
7
8
9
10
11
12
29
30
31
32
49
50
51
52
69
70
71
72
99
100