Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typo3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用sed,在单词1的第一次出现和单词2的最后一次出现之间提取文本_Sed - Fatal编程技术网

使用sed,在单词1的第一次出现和单词2的最后一次出现之间提取文本

使用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

我需要使用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 
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
命令就足够了(使用GNU
sed
):

/^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,这是多余的。