简体   繁体   English

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

[英]Delete two lines before a specific pattern using sed

Not much familiar with sed, I'm trying to delete 2 lines before a pattern (a timeout value and an empty line) and then reinsert both lines with updated timeout. 对sed不太熟悉,我试图删除模式前的2行(超时值和空行),然后用更新的超时重新插入两行。

Here's a part of the yaml file that I've: 这是我所拥有的yaml文件的一部分:

- id: phase1
  blahblahbal
  timeout: 720

- id: phase2
  blahblahbalh
  timeout: 1800

I'm trying to update first timeout to '900'. 我正在尝试将第一次超时更新为“ 900”。

Here's what I've with grep: 这是我对grep的看法:

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

and then inserting updated value with sed. 然后使用sed插入更新值。 This is working but the grep doesn't look nice. 这是可行的,但grep看起来不太好。 Is there a way to delete the two lines with sed before a pattern? 有没有一种方法可以删除模式前带有sed的两行?

Expected output after first sed/grep: 第一次sed / grep后的预期输出:

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

Expected output final: 最终预期输出:

- id: phase1
  blahblahbal
  timeout: 900

- id: phase2
  blahblahbalh
  timeout: 1800

This is how it could be done using awk ( back-replace2.awk ): 这是可以使用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 }
}

The line numbers of a timeout: line and an empty line are remembered. 会记住timeout:的行号timeout: line和空白行。 Thus, it can be checked whether these lines appeared exactly two lines before / one line before the line where the remarked pattern (here - id: phase2 ) matches. 因此,可以检查这些行是否与所标记的模式(此处为- id: phase2 )匹配的行恰好出现在前两行/前一行。

The variables buf1 and buf2 are used to make some kind of cycle buffering (ie the third last line is echoed for every line). 变量buf1buf2用于进行某种循环缓冲(即,每行最后一行的第三行回显)。

Therefore, the END rule is necessary to echo the rest of input (the contents of cycle buffers). 因此, END规则对于回显其余输入(循环缓冲区的内容)很有必要。

Test: 测试:

$ 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

$

Notes: 笔记:

  1. I didn't check the edge cases (eg whether files with less than 3 lines are handled correctly). 我没有检查边缘情况(例如,少于3行的文件是否正确处理)。

  2. The pattern matching and replacement may need additional logic. 模式匹配和替换可能需要其他逻辑。 I'm sure the questioner will be able to adjust the script appropriately. 我确定发问者将能够适当地调整脚本。

Here is my solution with sed: 这是我用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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM