【问题标题】:Using sed or awk how do you remove a pattern around a certian line使用 sed 或 awk 如何删除某行周围的模式
【发布时间】:2012-12-17 12:37:20
【问题描述】:

我需要删除某条线周围的图案:

#undef LZZ_INLINE
#ifdef LZZ_ENABLE_INLINE
#include "somename.inl"
#endif

应该变成:

#include "somename.inl"

我事先不知道somename。 如何使用例如sed 或 awk 以通用方式?

【问题讨论】:

  • 你不能确定 LZZ_ENABLE_INLINE 被定义了吗?
  • 这样的代码是由另一个工具自动生成的。我可以忍受它,但我想清理它并完全摆脱这个 LZZ 预处理器指令,因为我不使用它。所以这不是一个 c++ 问题,而是一个文本格式问题。由于其他人必须阅读代码并使用它,因此我不想要多余的定义,因为它们会增加复杂性并使代码混乱。

标签: shell unix sed awk


【解决方案1】:

如果文件大小允许读取一次将其全部加载到内存中,您可以这样做

sed -i.bk ':a;$!{N;ba}; s/#undef LZZ_INLINE\n#ifdef LZZ_ENABLE_INLINE\n\(#include [^\n]*\)\n#endif/\1/g' input.file

如果一切顺利,请删除 .bk 文件 :)

【讨论】:

  • 我需要一个合适的解决方案,所以这是完美的!!
  • @Martin 很高兴能帮上忙。您可以使用-i 代替-i.bksed 会自动删除“备份”。
  • 您介意详细说明一下声明的:a;$!{N;ba}; 部分发生了什么吗?
  • @nullrevolution 这部分将整个文件读入模式空间。它使用 label a,表示“读取另一个字符串并无条件地分支到 a,除非在最后一行”。在sed here 中查看更多关于流控制的信息。
【解决方案2】:

请试试这个 oneliner 是否适合您:

awk '/#undef LZZ_INLINE/{next;} /#ifdef LZZ_ENABLE_INLINE/{x=1;next;}x&&/#endif/{x=0;next;}1' file

【讨论】:

  • 我应该澄清一件事:如果可能的话,我需要像原地编辑一样批量执行此操作。简单地添加 -F 不起作用(我对 awk 不是很熟悉)
  • @Martin,awk 无法就地编辑。你必须awk '...' file > new && mv new file
  • 轻微修正,awk 可以就地编辑,但您需要对其进行编程。我将发布一个示例...
【解决方案3】:

将此添加到名为 fix.sed 的文件中

/^#undef LZZ_INLINE/{
N
N
N
s/.*\(#include "[^"]*"\).*/\1/
}

像这样运行:

sed -f fix.sed 你的原始文件

【讨论】:

  • 您的解决方案是有效的,但是您需要在 #include 行之前和之后的字符串上明确,否则您可能会产生误报。
  • 真的。最初的问题说它是机器生成的,所以我想你可以指望这个模式,但你确实提出了一个有效的观点。
【解决方案4】:

假设@glennjackman 发布了答案:

awk '/#undef LZZ_INLINE/{next} /#ifdef LZZ_ENABLE_INLINE/{x=1;next}x&&/#endif/{x=0;next} 1' file

是正确的,您只想就地更新输入文件,这是使用 awk 执行此操作的一种方法:

awk '/#undef LZZ_INLINE/{next} /#ifdef LZZ_ENABLE_INLINE/{x=1;next}x&&/#endif/{x=0;next} {out[++nr]=$0} END{close(FILENAME); for (i=1;i<=nr;i++) print out > FILENAME}' file

(即将1替换为{out[++nr]=$0} END{close(FILENAME); for (i=1;i&lt;=nr;i++) print out &gt; FILENAME}

这是另一个:

awk '/#undef LZZ_INLINE/{next} /#ifdef LZZ_ENABLE_INLINE/{x=1;next}x&&/#endif/{x=0;next} {print > "/tmp/\""FILENAME"\"" } END{system("mv /tmp/\""FILENAME"\" \""FILENAME"\""}' file

(即将1替换为{print &gt; "/tmp/\""FILENAME"\"" } END{system("mv /tmp/\""FILENAME"\" \""FILENAME"\""}

如何实现它有一些变化,但基本思想只是缓冲输出,直到您完成读取输入文件然后覆盖输入文件。 NBD 无论哪种方式...

我应该提到的另一个变体是创建一个 tmp INPUT 文件,它看起来像这样:

awk '
BEGIN{
   tmp="/tmp/\"" ARGV[1] "\""
   while ( (getline var < ARGV[1]) > 0 ) {
      print var > tmp
   }
   close(tmp)
   out = ARGV[1]
   ARGV[1] = tmp
}
/#undef LZZ_INLINE/{next} /#ifdef LZZ_ENABLE_INLINE/{x=1;next}x&&/#endif/{x=0;next} {print > out}' file

您使用 system("mv...") 还是 getline 循环是风格还是取决于您的操作系统提供的内容。

【讨论】:

    猜你喜欢
    • 2020-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-31
    • 2023-01-26
    • 1970-01-01
    • 2013-02-27
    相关资源
    最近更新 更多