【问题标题】:Use sed to change first occurrence after match使用 sed 更改匹配后的第一次出现
【发布时间】:2015-09-04 14:04:14
【问题描述】:

我已经制定了在匹配后替换 sed 的语法,但它会替换匹配后的所有实例。有人可以告诉我我在这里做错了什么。我知道这是小事,但我似乎无法接受。

sed -e "0,/\#NOTE/!  s/$NEW_VVER/$CURRENT_VER/" FILE1 > FILE2

我也试过了

sed -e "0,/\#NOTE/!  s/$NEW_VVER/$CURRENT_VER/1" FILE1 > FILE2

这是完整的 sed 命令和要更改的数据。

sed -e "0,/\#NOTE/!  s/$NEW_VVER/$CURRENT_VER/" -e "0,/\#NOTE/!  s/$NEW_VER/$VER/" -e "0,/\#NOTE/!  s/$EVEN_LENGTH/$OLD_EVEN_LENGTH/" -e "0,/\#NOTE/!  s/$ODD_LENGTH/$OLD_ODD_LENGTH/" -e "0,/\#NOTE/!  s/$START_DIGIT/$OLD_START_DIGIT/" -e "0,/\#NOTE/!  s/$STRING/$OLD_STRING/ FILE1 > FILE2"

基本上它应该找到字符串“#NOTE”并只替换匹配后的第一个实例。

    #CHANGE THESE EVERY VERSION
#NOTE: Don't forget to add the needed variables to the version arguments. 
   DEFAULT_VERSION = REPVVER
   EVEN_LENGTH = REPELENGTH 
   ODD_LENGTH = REPOLENGTH  
   CURR_VERSION = "REPVVER"
   START_DIGIT = REPSTARTDIGIT
###########################################

例如,它应该找到字符串“#NOTE”并将“REPVVER”字符串替换为新值。但它不仅会取代那个,而且会取代所有后续。

【问题讨论】:

  • 请显示示例数据(例如 3-10 行输入)和示例输出。为 NEW_VVERCURRENT_VER 显示合适的值可能会有所帮助。双V是故意的吗?如果是的话也没问题;如果不是,那将是一个大问题。
  • 请在您的问题中添加示例输入和该示例输入所需的输出。
  • 是的,双 V 是有意的 这是它应该改变的 #NOTE: Don't forget to add the needed variables to the version arguments. DEFAULT_VERSION = REPVVER 它应该只改变 REPVVER 的实例,但它会改变 REPVVER 的所有实例
  • 请注意,0 作为地址范围的下限是 GNU 扩展。
  • 那么要替换的字符串与#NOTE出现在同一行,还是在下一行?

标签: bash sed


【解决方案1】:
sed -e '/#NOTE/!b' -e ':a' -e "s/$NEW_VVER/$CURRENT_VER/;t trail" -e 'n;ba' -e ':trail' -e 'n;btrail' FILE1 > FILE2
  • posix 兼容和 oneliner(将所有 ' -e ' 替换为多行脚本的新行(也 " 并替换周围的 'by " 以进行变量解释)
  • #NOTE 之后更改NEW_VVER 的第一次出现但不在同一行(假设#note 是注释行)。 Linne 可能排在#NOTE 之后的第 50 位
  • 假设NEW_VVERCURRENT_VER 的内容符合正则表达式(转义元字符,如&

【讨论】:

  • 很有意思,你能多解释一下其余部分吗?
  • 我无法让它在 Ubuntu 上运行。
【解决方案2】:

这里有一个比较粗略的方法:

sed -e "/\#NOTE/,/./  s/$NEW_VVER/$CURRENT_VER/" FILE1 > FILE2

这将替换限制为包含#NOTE 的行和下一行。每行最多执行一次。

这种方法假定替换不会改变#NOTE 行上的任何内容。该假设适用于您的示例数据,但您必须确定它是否总体上可以接受。

更新:

如果执行替换的行没有紧跟#NOTE 行,如果您可以依赖$NEW_VVER 的值不包含任何正则表达式元字符,那么您可以通过上面的这种变化来做到这一点:

sed -e "/\#NOTE/,/$NEW_VVER/  s/$NEW_VVER/$CURRENT_VER/" FILE1 > FILE2

在这种情况下,应用替换的行范围从一个匹配的/\#NOTE/ 开始,到下一个匹配/$NEW_VVER/ 的行结束。如上所述,这假设替换不会改变 /\#NOTE/ 行中的任何内容。

【讨论】:

  • 很遗憾,这不起作用,因为我要进行多项更改,而且它们并非都在匹配项的正下方。
  • 我试过了,它确实(安全地)替换了 同一行#NOTE 之后的第一个匹配项(不确定这是个问题吗?);也适用于旧版本的 GNU,这总是一个好处。
  • @l'L'l,是的,正如我已经提到的,替换将在 #NOTE 行上执行。 OP 将不得不决定这是否是一个问题。
  • @leigon,考虑一下我添加的替代方案。它的限制稍微多一些,因为要替换的字符串不能包含正则表达式元字符,但这对于您的示例数据来说不是问题。
  • 你能分解一下它是如何工作的吗?它几乎就在那里看到了一些随机变量进入错误位置的问题。
猜你喜欢
  • 1970-01-01
  • 2012-02-27
  • 2013-09-30
  • 2021-12-11
  • 1970-01-01
  • 2020-04-27
  • 2018-11-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多