【问题标题】:how to replace pattern in multi-line in linux如何在linux中替换多行中的模式
【发布时间】:2014-05-24 19:10:04
【问题描述】:

假设我有一个名为 text.txt 的文件 在 text.txt 中,我有许多以下模式:

/**
 * @something
**/

我想将此模式替换为空字符串。执行此操作的最简单的 Linux 命令是什么?

  1. “grep”不起作用,因为这是多行模式。
  2. 我尝试了“sed”,但无法正常工作。
  3. 我想“awk”可能很容易,但“awk”似乎很复杂,我对“awk”并不熟悉。

【问题讨论】:

  • sed 绝不应尝试用于任何多行问题,它严格用于单行替换。 awk 并不复杂,它只需要一个小的范式转换即可使用它,因为它默认提供了许多您必须在其他工具/语言中手动编写的用于解析文本文件的功能(例如读取行、拆分为字段)等)但是一旦你使用了几次,它并不比任何其他基于 Algol 的语言复杂。
  • 您会根据对需求的几种不同解释获得答案。如果您提供一个真正具有代表性的输入文件(即包含至少 2 个您想要删除的模式的文件)和相关的预期输出,您最有可能获得可靠的答案。

标签: regex linux command-line sed awk


【解决方案1】:

假设我们的输入文件是:

$ cat text.txt
before
/**
 * @something
**/
after

我们可以过滤掉带有awk的cmets:

$ awk '/\/\*\*/ {c=1; next} /\*\*\// {c=0; next} c==0 {print}' text.txt
before
after

awk 的工作原理是将一个变量作为一个名为 c 的标志。当我们开始时,c=0 表示我们不在评论中。当注释开始行出现时,/**,我们设置c=1c 保持为 1,直到出现下一个注释结尾行 **/,在这种情况下,c 被设置回 0。仅当 c=0 时才打印出该行。不会打印打开和关闭注释行之间的任何内容,无论格式如何。

代码看起来很有趣,因为/* 都是awk 的活动字符。所以,他们都需要用反弹来逃避。因此,例如,用于查找注释开头行的正则表达式类似于\/\*\*,而用于注释结尾行的正则表达式类似于\*\*\/

更复杂的输入文件

假设输入文件具有更复杂的结构,如 JS 示例所示:

$ cat file
something
/**
 * @something
**/ random
hello
hi /**
 * @something
**/ bye
hola
gracias
bye

我们可以使用awk 处理这个问题,如下所示:

$ awk -v RS='\\*\\*/\n*' '{sub(/\n*\/\*\*.*/,"",$0); print $0}' file
something
 random
hello
hi 
 bye
hola
gracias
bye

以上内容已使用 GNU awk 进行了测试。由于它使用多字符记录分隔符,它可能不适用于旧版本的awk

虽然awk 通常逐行读取文件,但在我们上面的版本中,我们设置了记录分隔符RS,以匹配注释的结尾。然后,我们删除从评论开始到记录结尾的所有内容并打印记录。

【讨论】:

  • 你可以通过改变它的顺序来简化它。这样您就不需要next 语句。看我的帖子。
【解决方案2】:
cat text.txt | egrep -v "[/]" | egrep -v "[*] @" > newtext.txt

会这样做,但您可能需要根据文件中的其他内容稍作修改。

【讨论】:

  • UUOC 并且需要的不仅仅是轻微的修改才能成为一个强大的解决方案
【解决方案3】:

这是一个简单的awk 将文本从给定模式中删除:

cat file
before
/**
 * @something
**/
after

awk '/\*\*\//{f=0} f; /\/\*\*/{f=1}' file
 * @something

当您不喜欢包含 START/END 模式时,这是处理此问题的最简单的awk 之一:

awk '/END/{f=0} f; /START/{f=1}'

【讨论】:

    【解决方案4】:

    使用 GNU awk for multi-char RS 将整个文件作为一个字符串读取:

    如果您特别想删除您发布的字符串,那就是:

    $ cat file
    foo/**
     * @something
    **/bar and more/**
     * @something
    **/stuff
    
    $ awk -v RS='^$' -v ORS= -v pat='/**
     * @something
    **/' '{
        while ( s=index($0,pat) ) {
            $0 = substr($0,1,s-1) substr($0,s+length(pat))
        }
        print
    }' file
    foobar and morestuff
    

    或者,如果您实际上只是想删除每次出现 /**/ 之间的所有内容,您只需要:

    awk -v RS='/[*][*][^/]+/' -v ORS= '1' file
    foobar and morestuff
    

    【讨论】:

      猜你喜欢
      • 2020-07-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-04
      相关资源
      最近更新 更多