使用sed,在单词1的第一次出现和单词2的最后一次出现之间提取文本
我需要使用sed提取第一次出现的名为“BEGIN”的单词和最后一次出现的名为“END”的单词之间的文本 输入:使用sed,在单词1的第一次出现和单词2的最后一次出现之间提取文本,sed,Sed,我需要使用sed提取第一次出现的名为“BEGIN”的单词和最后一次出现的名为“END”的单词之间的文本 输入: line1 BEGIN line2 line3 END line4 line5 BEGIN line6 line7 ENDED END line8 END line9 line10 BEGIN line2 line3 END line4 line5 BEGIN line6 line7 ENDED END line8 END 预期输出: line1 BEGIN line2 li
line1
BEGIN
line2
line3
END
line4
line5
BEGIN
line6
line7
ENDED
END
line8
END
line9
line10
BEGIN
line2
line3
END
line4
line5
BEGIN
line6
line7
ENDED
END
line8
END
预期输出:
line1
BEGIN
line2
line3
END
line4
line5
BEGIN
line6
line7
ENDED
END
line8
END
line9
line10
BEGIN
line2
line3
END
line4
line5
BEGIN
line6
line7
ENDED
END
line8
END
我的方法:
line1
BEGIN
line2
line3
END
line4
line5
BEGIN
line6
line7
ENDED
END
line8
END
line9
line10
BEGIN
line2
line3
END
line4
line5
BEGIN
line6
line7
ENDED
END
line8
END
它在开始和结束之间提取文本。这里有两个BEGIN和END语句,我的解决方案提取这些单词之间的文本。
我的解决方案在第一次出现word1(BEGIN)和最后一次出现word2(END)之间提取文本失败
如果文件足够小,足以容纳内存:
$ perl -0777 -ne 'print /(^BEGIN\n.*^END\n)/ms' ip.txt
BEGIN
line2
line3
END
line4
line5
BEGIN
line6
line7
ENDED
END
line8
END
通过2次传递的方法避免在内存中存储任何文本,这样它就可以用于任何大小的输入文件,并通过1次调用1个标准UNIX工具来避免生成多个子shell,以下方法可以在每个UNIX框的任何shell中使用任何awk:
$ awk '
NR==FNR{ if (!beg && /BEGIN/) beg=NR; if (/END/) end=NR; next}
(beg <= FNR) && (FNR <= end)
' file file
BEGIN
line2
line3
END
line4
line5
BEGIN
line6
line7
ENDED
END
line8
END
$awk'
NR==FNR{if(!beg&&/BEGIN/)beg=NR;if(/END/)END=NR;next}
(beg一个一行的sed
命令就足够了(使用GNUsed
):
/^BEGIN$/,$!d;
删除第一个开始上方的行。:a;/(^ |\n)。*END$/{p;d};$d;n;ba
将(“slurps”)行累积到模式空间中。每当读取结束行时,将打印出累积的行,并从新周期开始删除模式空间。请注意,此“slurps”如果输入太大,接近速度可能很慢,甚至可能使sed
进程崩溃
输入文件的内容:
line1
BEGIN
line2
line3
END
line4
line5
BEGIN
line6
line7
ENDED
END
line8
END
line9
line10
并使用GNU sed 4.8
sed -E '/^BEGIN$/,$!d; :a; /(^|\n).*END$/{p;d}; $d; N; ba' inputfile
印刷品
BEGIN
line2
line3
END
line4
line5
BEGIN
line6
line7
ENDED
END
line8
END
另一种办法是:
lastend=$(sed -n '/^END$/=' inputfile | tail -1)
[[ -n $lastend ]] && sed -n "/^BEGIN\$/,${lastend}p" inputfile
这种双通道方法不会出现“咕噜咕噜”的线条。这可能适合您(GNU-sed):
sed-n'/\/{x;:a;n;/\/{x;p;ba};H;$!ba;x;//p}文件
使用-n
选项设置自动打印关闭,然后将焦点放在包含单词BEGIN
的行之后的行上
交换到保留空间(HS)并启动一个循环以获取下一行,如果该行包含单词END
交换到HS,则打印其内容并重复
如果当前行不包含单词END
,请将当前行附加到HS,除非它是文件的结尾,否则重复
在文件末尾,如果HS的第一行开始结束
,则打印HS的第一行,以及允许文件处理终止的任何条件
因此,只有在看到单词BEGIN
时,才会对行进行处理,并且每次出现单词END
时,都会打印这些行。基本上是在保留空间中从最后一行缓冲到下一行。#1.查找开始。#2.查找结束。#3.在保留空间中缓冲每一行。#nt保留空间,清除保留空间并转至步骤3。使用ed
,printf“%s\n”“/BEGIN/,?END?p”| ed-s logs.txt,任何涉及查找文件中最后一个X的操作都比较容易:sed-n'/BEGIN/='
也可以使用sed-n'/END/='
而不是grep+cut
…和sed-n'/BEGIN/{q;}“
以避免head
以及将其复制/粘贴到中,并查看是否存在某些问题。此外,这将读取输入文件3次,并生成7个子shell,这是多余的。