使用多行模式在 sed 中进行搜索和替换

使用多行模式在 sed 中进行搜索和替换

我有一个文件,其内容如下:

alfa
[many lines here]
TAG1
TAG2

bravo
TAG3

charlie
TAG4
[many lines here]

其中 TAG1、TAG2、TAG3 和 TAG4 是固定字符串,而 alfa、bravo 和 charlie 会随时间变化,我想要提取:

alfa-bravo-charlie

我必须使用什么精确的 sed 命令?我不知道如何使用多行模式。:(

附言:我在 Windows 上使用 sed。

答案1

这适用于 gnu sed,我认为它不依赖于任何 gnu 特定的扩展,但我不知道。

echo "$yourdata" | sed -ne '1{h;d}; /^TAG1$/ {n; /^TAG2$/{n;N;N; /\nTAG3$/ {s///; H; n;N;N; /\nTAG4$/ {s///; H; g; s/\n\n/-/gp; q; } } } }'

结果:alfa-bravo-charlie

它是如何工作的?首先我们告诉 sed “-n” 我们要不是打印任何内容,除非我们特别说[p] print。

sed 表达式的第一个块是“1{h;d}”。这表示当我们读取第 1 行时,将该行存储在 [h]old 缓冲区中,然后从工作缓冲区 [d]elete 中将其删除,以便我们读取下一行并从头开始将其传递给 sed 表达式。

读取后续行时将跳过“1{...}”块。

在到达 TAG1 行之前,我们不会再匹配任何内容。此时,我们执行长 {...} 块。这表示首先读取 [n]ext 行,覆盖缓冲区中的 TAG1 行。如果缓冲区现在是 TAG2,则我们执行下一个内部 {...} 块。首先读取 [n]ext 行,覆盖缓冲区中已有的内容。接下来的两个命令是“N;N”。这意味着读取接下来的 2 行,但附加将它们添加到工作缓冲区,而不是覆盖它。如果工作缓冲区现在匹配 /\nTA​​G3$/,那么我们执行下一个内部 {...} 块。这表示首先使用“s///”,换句话说,用空字符串替换最近匹配的表达式。这会从工作缓冲区的末尾删除“\nTAG3”,留下“\nbravo”。然后我们执行 [H],将其附加到保持缓冲区。([h] 覆盖保持缓冲区,[H] 附加到它)。所以现在保持缓冲区包含第一行“alfa”,然后是下一行“\nbravo”。它们由换行符连接,所以我们实际上得到了“alfa\n\nbravo”。我们稍后会处理这两个换行符。

我们继续,直到在保持缓冲区中得到“alfa\n\nbravo\n\ncharly”。然后我们说 [g]et 保持缓冲区(覆盖工作缓冲区中的所有内容)。我们在此执行“s/\n\n/-/”以将双换行符变成破折号。我们在 [s] 命令的末尾添加“g”和“p”标志,以便替换全局有效(即不只是进行一次替换然后停止),并且替换后的结果被 [p] 打印。

然后我们退出,我们不需要读取输入流的其余部分。

答案2

从您的示例中无法清楚看出您到底想要做什么。听起来您试图丢弃文件中除一组三个标记之外的所有内容,而您想要将它们连接在一起。您不需要 sed 来实现这一点,只需输入:

echo alfa-bravo-charlie

你已经实现了目标。如果你只是想删除“alfa”和“charlie”之间的内容,你可以使用如下 sed 脚本:

/charlie/ a\
alfa-bravo-charlie
/alfa/,/charlie/ d

如果这不是您想要做的,那么澄清一下您的例子可能会有所帮助。

相关内容