打印两个模式之间的所有内容,然后删除结果输出的第一行和最后一行

打印两个模式之间的所有内容,然后删除结果输出的第一行和最后一行
otherdata
otherdata
start_data
one
two
three
four
end_data
otherdata
otherdata

结果输出应该是:

one
two
three
four

sed对我来说这看起来像是一份工作:

sed -n '/start_data/,/end_data/{1d;$d;p}' myfile

不工作。第一行被删除,但最后一行没有被删除! (到目前为止我无法用逻辑解释任何原因)

好吧,让我们尝试一下丑陋的方法:

sed -n '/start_data/,/end_data/{/start_data\|end_data/!p}' myfile

公平地说,这有效。但我想让更短的方法也能发挥作用,因为结果输出将总是在第一行和最后一行包含两种模式,因为我们只提取中间的数据。

为什么sed尝试将1dand$d语句组合在花括号中会令人窒息?

答案1

您可以反转逻辑:

sed '1,/start_data/d;/end_data/,$d'

假设start_data不在第一行。要解决这个问题,如果您有 GNU sed,您可以改为:

sed '0,/start_data/d;/end_data/Q'

0Q是 GNU 特定的。Q退出sed而不打印模式空间,因此这也将使其更加高效,因为它不会像第一个解决方案那样继续读取和丢弃文件的其余部分。

答案2

awk似乎很适合这个问题:

$ awk '/end_data/{f=0;};f{print;};/start_data/{f=1;}' myfile
one
two
three
four

上面使用标志f来决定是否应该打印一行。当 时start_data,标志设置为 true (1)。当end_data找到时,该标志被设置为假(0)。当f为 true 时,将打印该行。

为什么 sed 在尝试将 1d 和 $d 语句组合在花括号中时会窒息?

这不是“窒息”。它只是1d$d文件中的第一行和最后一行,而不是模式中的第一行和最后一行。

答案3

嗯,这有效:

sed -ne/start_data/!d\;:n -e'n;/end_data/q;p;bn' <in

它甚至不会尝试print ,直到遇到/start_pattern/并且从该地址一直到最后一行,如果换行符拉入 matches ,它将用next, uit 输入完全替换当前行,否则rint 。这就是全部。根据您的示例数据,输出为:q/end_data/p

one
two
three
four

它不会将一行识别为end_data如果它也匹配第一个则匹配start_data输入中出现的行。

答案4

在这里,让我对问题中提供的输入文件进行简单的修饰修改:

% cat myfile
red
orange
start_data
one
two
three
four
end_data
yellow
green

我只是otherdata用不同的其他数据替换了这些行,因此我们可以通过内容唯一地引用输入文件中的每一行,而不必说“第一行”,因为这显然会受到误解,或者“第一行otherdata” ”,这有点冗长(而且据我所知,也可能会受到误解)。

现在,您可能会发现与第一次尝试最接近的事情是

% sed -n '/start_data/,/end_data/p' myfile | sed '1d;$d'
one
two
three
four

你的第一次尝试 ( sed -n '/start_data/,/end_data/{1d;$d;p}' myfile) “窒息”,因为(正如 John1024 所说) line1red* ,而 line$green**。没有1d;$d;任何效果,因为这些行(事实上,全部/colordata行otherdata)已被/start_data/,/end_data/范围排除。
__________
* 即,第一行全部的输入文件,不仅仅是匹配的范围
**,即最后一行全部的输入文件,不仅仅是匹配范围


顺便问一下,您是说您的命令产生了以下输出吗?

one
two
three
four
end_data

因为这没有意义,除非start_data 曾是第 1 行(即,如果redorange不存在)。

相关内容