【问题标题】:How to replace a whole line (between 2 words) using sed?如何使用 sed 替换整行(两个单词之间)?
【发布时间】:2021-10-08 08:02:21
【问题描述】:

假设我的文本为:

This is a sample text.
I have 2 sentences.
text is present there.

我需要替换两个“文本”单词之间的整个文本。所需的解决方案应该是

This is a sample text.
I have new sentences.
text is present there.

我尝试使用以下命令,但它不起作用:

sed -i 's/text.*?text/text\
\nI have new sentence/g' file.txt

【问题讨论】:

    标签: shell awk sed


    【解决方案1】:

    您已经使用awk 解决了您的问题,但如果其他人将来会寻找sed 解决方案,这里有一个sed 脚本可以满足您的需求。诚然,该脚本使用了一些高级 sed 功能,但这就是其中有趣的部分 :)

    替换.sed
    #!/usr/bin/env sed -nEf
    
    # This pattern determines the start marker for the range of lines where we
    # want to perform the substitution. In our case the pattern is any line that
    # ends with "text." — the `$` symbol meaning end-of-line.
    /text\.$/ {
      # [p]rint the start-marker line.
      p
    
      # Next, we'll read lines (using `n`) in a loop, so mark this point in
      # the script as the beginning of the loop using a label called `loop`.
      :loop
    
      # Read the next line.
      n
    
      # If the last read line doesn't match the pattern for the end marker,
      # just continue looping by [b]ranching to the `:loop` label.
      /^text/! {
        b loop
      }
    
      # If the last read line matches the end marker pattern, then just insert
      # the text we want and print the last read line. The net effect is that
      # all the previous read lines will be replaced by the inserted text.
      /^text/ {
        # Insert the replacement text
        i\
    I have a new sentence.
    
        # [print] the end-marker line
        p
      }
    
      # Exit the script, so that we don't hit the [p]rint command below.
      b
    }
    
    # Print all other lines.
    p
    

    用法

    $ cat lines.txt
    foo
    This is a sample text.
    I have many sentences.
    I have many sentences.
    I have many sentences.
    I have many sentences.
    text is present there.
    bar
    $
    $ ./replace.sed lines.txt
    foo
    This is a sample text.
    I have a new sentence.
    text is present there.
    bar
    

    【讨论】:

    • 一个优雅的解决方案,但是应该注意,如果在包含分隔词的行的上方或下方有其他行,它们也不会被打印。 OP 不清楚这是否是有意的,但如果是这样,则可以使用三行解决方案将原始文件替换为一个。
    • @potong 是的,你是对的。我错过了处理那个案例,这可能是 OP 的问题所需要的。喜欢代码审查的另一个原因:)
    • 如果你喜欢代码审查,我可以提供更多吗?首先,. 匹配任何单个字符,所以我认为您打算使用\.。其次,{...} 组命令但对于单个命令是不必要的,所以/^text/! b loop 就足够了。第三,由于该单个命令是流控制,因此它推断出后面的任何内容都匹配,因此不需要另一个匹配。最后,由于调用了-n 选项,因此需要p 命令或标志来打印行,并且应该将其放置在构成解决方案的命令链之外,作为包罗万象的解决方案。 HTH
    • @potong 谢谢!确实很有帮助。 1)是的,你是对的,我总是被它绊倒,即使我知道它是 REs 中的一个特殊字符; 2)。在这里使用大括号只是一种风格选择——我觉得它们更好地传达了命令对模式的归属; 3)你说得对,结束标记匹配可以省略; 4)我同意,在您发表评论前几秒钟,我实际上已经修改了答案。再次感谢您的评论!
    【解决方案2】:

    I need to replace whole text between two 'text' words.

    如果我理解,第一个 text.(带点)在第一行的末尾,第二个 text 在第三行的开头。使用awk,您可以获得the required solution 将值添加到var s:

    awk -v s='\nI have new sentences.\n' '/text.?$/ {s=$0 s;next} /^text/ {s=s $0;print s;s=""}' file
    This is a sample text.
    I have new sentences.
    text is present there.
    

    【讨论】:

      【解决方案3】:

      替换

      sed -i 's/I have 2 sentences./I have new sentences./g'

      sed -i 's/[A-Z]\s[a-z].*/I have new sentences./g'

      插入

      sed -i -e '2iI have new sentences.' -e '2d'

      【讨论】:

      • 如果我不知道 'text' 和 'text' 之间有多少个句子呢?那你的替代品是如何工作的呢?
      • @saiakhil 如果您不知道要替换什么,则无法替换。您将需要一个模式来替代。您可能需要额外的运算符,例如分支标签和N; n; 用于新行替换。 gnu.org/software/sed/manual/sed.html
      【解决方案4】:

      使用您展示的示例,请尝试以下操作。 sed 不支持正则表达式中的惰性匹配。使用awk 的 RS,您可以仅使用显示的示例进行替换。您需要创建变量 val,其中包含新值。然后在awk 中执行简单的替换操作,这样剩下的就可以得到你预期的输出了。

      awk -v val="your_new_line_Value" -v RS="" '
      {
        sub(/text\.\n*[^\n]*\n*text/,"text.\n"val"\ntext")
      }
      1
      ' Input_file
      

      上面的代码将在终端上打印输出,一旦您对上面的结果感到满意并希望将输出保存到 Input_file 本身然后尝试下面的代码。

      awk -v val="your_new_line_Value" -v RS="" '
      {
        sub(/text\.\n*[^\n]*\n*text/,"text.\n"val"\ntext")
      }
      1
      ' Input_file > temp && mv temp Input_file
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-04-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-17
        • 2012-10-25
        • 2022-01-14
        相关资源
        最近更新 更多