使用 sed 删除特定模式之前的两行

Posted

技术标签:

【中文标题】使用 sed 删除特定模式之前的两行【英文标题】:Delete two lines before a specific pattern using sed 【发布时间】:2017-10-13 04:47:17 【问题描述】:

对 sed 不太熟悉,我正在尝试删除模式前的两行(超时值和空行),然后用更新的超时重新插入两行。

这是我拥有的 yaml 文件的一部分:

- id: phase1
  blahblahbal
  timeout: 720

- id: phase2
  blahblahbalh
  timeout: 1800

我正在尝试将第一次超时更新为“900”。

这是我用 grep 完成的:

grep -v "$(grep -B 2 'id: phase2' test.yaml | grep -v 'id: phase2')" test.yaml > test.yaml

然后使用 sed 插入更新的值。这是有效的,但 grep 看起来不太好。有没有办法在模式前用 sed 删除两行?

第一次 sed/grep 后的预期输出:

- id: phase1
  blahblahbal
- id: phase2
  blahblahbalh
  timeout: 1800

预期的最终输出:

- id: phase1
  blahblahbal
  timeout: 900

- id: phase2
  blahblahbalh
  timeout: 1800

【问题讨论】:

显示您的预期输出。 相对于模式删除是困难的,当模式遵循需要删除的内容时更是如此。 @JonathanLeffler 该评论有何帮助? 您的预期输出没有删除行?您刚刚更换了号码。那是你真正想要的吗? 这是最终输出。 【参考方案1】:

这是我使用 sed 的解决方案:

# Remove above two lines before phase2 id
sed -i ':a;N;s/\n/&/2;Ta;/\n- id\: phase2$/s/.*\n//;P;D' test.yaml

# Add updated timeout
sed -i "/- id\: phase2/ i\\
    timeout: 900\\
" test.yaml

【讨论】:

我知道 sed 不仅仅是 s (替代),但我从来没有能够掌握它。虽然,由于 awk 的存在,我的积极性很低...... 大声笑,我刚刚从其他地方复制了第一个 sed。没有得到该命令中实际发生的情况。【参考方案2】:

这就是使用 awk (back-replace2.awk) 的方法:

$1 ~ /timeout:/  lineTimeOut = NR 
/^[ \t\r]*$/  lineEmpty = NR 
/- id: phase2/ 
  if (lineTimeOut == NR - 2 && lineEmpty == NR - 1) 
    buf1 = "  timeout: 900"
  


  if (NR > 2)  print buf1 
  buf1 = buf2 ; buf2 = $0

END 
  if (NR >= 2)  print buf1 
  if (NR >= 1)  print buf2 

记住timeout: 行和空行的行号。因此,可以检查这些行是否恰好出现在与注释模式(此处为- id: phase2)匹配的行之前/之前的两行。

变量buf1buf2 用于进行某种循环缓冲(即每行都回显倒数第三行)。

因此,END 规则对于回显其余输入(循环缓冲区的内容)是必要的。

测试:

$ cat >back-replace2.txt <<EOF
- id: phase1
  blahblahbal
  timeout: 720

- id: phase2
  blahblahbalh
  timeout: 1800
EOF

$ awk -f back-replace2.awk back-replace2.txt 
- id: phase1
  blahblahbal
  timeout: 900

- id: phase2
  blahblahbalh
  timeout: 1800

$

注意事项:

    我没有检查边缘情况(例如,是否正确处理了少于 3 行的文件)。

    模式匹配和替换可能需要额外的逻辑。我相信提问者能够适当地调整脚本。

【讨论】:

谢谢@Scheff。我也找到了另一种方法(作为答案添加)。

以上是关于使用 sed 删除特定模式之前的两行的主要内容,如果未能解决你的问题,请参考以下文章

使用 Bash (sed?) 删除包含特定文本 (regex) 的多行 /* ... */ 样式注释

如何删除仅通过 ID 不同的两行

sed 或 awk:删除模式后面的 n 行

搜索以特定模式结尾的列,然后删除该列

sed简单使用选择性删除

使用 sed 从文本文件中删除特定的行号?