【问题标题】:sed: replace block of text between markers INCLUDING the markers themselvessed:替换标记之间的文本块,包括标记本身
【发布时间】:2017-02-16 11:55:31
【问题描述】:

我有以下 sed 命令,它们分别用开始和结束标记 /**#@+**#@-* 之间的文件内容替换文本块:

sed -i -ne '/**#@+/ {p; r block.txt' -e ':a; n; /**#@-*/ {p; b}; ba}; p' -e '/**#@+/d' test.txt && sed -i -e '/**#@+/d' -e '/**#@-*/d' test.txt

(除了替换文本外,该命令还转换行尾。)

事实上,这使开始和结束标记保持不变,但我也想摆脱它们。 My using the p command means that I can't have a d command in the same execution unit。我通过引入第二组删除这些标记的命令来解决该问题,但如果可能的话,我希望将所有这些都包含在一个 sed 命令中。

test.txt

start of file

/**#@+
 * the start marker is above
 */
this should get replaced
/**#@-*/
end marker is above

block.txt

THIS IS THE REPLACEMENT

结果

运行命令应该像这样改变 test.txt:

start of file

THIS IS THE REPLACEMENT
end marker is above

我正在寻找 sed 中最短的单行解决方案。

【问题讨论】:

  • 请添加示例输入/输出以进行测试
  • 你想让我们试穿什么?一个示例文件会很有帮助。
  • 我已经从正则表达式中删除了行结束位并包含示例输入、输出和替换文件
  • p 命令只打印模式空间中的内容,它们对程序流程没有影响。 d 删除模式空间并结束程序流程,d 之后的任何命令都不会被执行(除非bt 命令被定向到d 命令之后的: 占位符)。
  • @potong 感谢您的解释,很好学习

标签: linux bash sed


【解决方案1】:

这可能对你有用(GNU sed):

sed '/^\/\*\*#@+/,/^\/\*\*#@-\*/cThis is the replacement' file

这会将范围之间的行更改为所需的字符串。

用文件内容替换范围:

sed -e '/^\/\*\*#@+/!b;:a;N;/^\/\*\*#@-\*/M!ba;r replacementFile' -e 'd' file

在遇到范围的开始时设置一个循环来收集模式空间中的范围,然后将替换文件读入标准输出并删除模式空间的内容。

【讨论】:

  • 正是我想要的,非常感谢。不能说我完全理解了,尤其是M!ba;r 的部分,但是嘿,它有效
【解决方案2】:

您的开始和结束标签包含正则表达式元字符和/sed 仅通过正则表达式搜索输入,您需要转义 / 以及 sed 中的所有元字符。

awk 中处理这个问题要容易得多,因为awk 也允许非正则表达式纯文本搜索:

awk -v st='/**#@+' -v et='/**#@-*/' -v repl="$(<block.txt)" '
   $0 == st{del=1} $0 == et{$0 = repl; del=0} !del' file

start of file

THIS IS THE REPLACEMENT
end marker is above

【讨论】:

  • 感谢 anubhava,但如前所述,我正在寻找仅 sed 的解决方案。元字符似乎对命令没有影响:我不过滤斜杠并且替换工作正常。
  • 祝你好运sed。尽管我可以但不想为这项任务推广错误的工具
  • btw 进一步澄清元字符,您的 sed 实际上并没有搜索完整的起始标签。例如sed -n '/**#@+/p' file 还会找到只是 #@+ 而不是完整的 /**#@+ 的行
  • 谢谢,注意斜线。没什么大不了的。另外,sed对我来说很好,你能提到如何用sed解决这个问题吗?欣赏它。
  • 看看potong的回答你就会明白我为什么要回避sed
【解决方案3】:

虽然您说:正在寻找 sed 命令,但您可能会感兴趣使用 Perl

perl -lae '$.==1 ? (@b="@F") : (@f="@F") && s|(^[\s+/]).*|| ||
           ( print /this/ ? "@b" : "@f" )  ' block file  

输出

start of file

THIS IS THE REPLACEMENT
end marker is above  

【讨论】:

  • 我确实在寻找 sed 中的解决方案,但是仍然感谢 perl 中的课程! :)
  • @foshpumpa 希望如此 :)
猜你喜欢
  • 2014-11-28
  • 1970-01-01
  • 2012-07-09
  • 1970-01-01
  • 2015-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-13
相关资源
最近更新 更多