【问题标题】:Replace multiple lines using sed in a bash script在 bash 脚本中使用 sed 替换多行
【发布时间】:2020-09-22 01:19:34
【问题描述】:

我有一个包含多行的文件。我正在寻求帮助以仅修改与正则表达式模式匹配的这些行,然后在每个结果后添加一些文本。 我用的是mac,但是bash脚本会在linux上运行,不知道有没有关系。

someText
StringToSearch:
    | isoCode |

someOthertext
StringToSearch:
    | isoCode |

againSomOtherText
StringToSearch:
    | isoCode |

在匹配“StringToSearch:”之后,我需要在每个“| isoCode |”之后添加“| uk |”,因此结果将类似于:

someText
StringToSearch:
    | isoCode |
    | uk |

someOtherText
StringToSearch:
    | isoCode |
    | uk |

againSomeOtherText
StringToSearch:
    | isoCode |
    | uk |

我的正则表达式是^\s*StringToSearch:\n[^\n]+,完整的工作示例可在link 之后的regex101 获得

我不知道如何使用 sed 在 bash 中实现它。

其实我的sed是这样的:sed -E 's,\^\s*StringToSearch:\n\([^\n]+\),| uk |,' < inputFile

【问题讨论】:

  • 默认情况下 sed 逐行工作.. 所以你不能匹配\n 或执行多行匹配而不做一些额外的神秘事情.. 另外,regex101 不适合 grep 之类的 cli 工具/sed/awk 因为正则表达式的语法和功能有很大的不同
  • 作为sed 的替代品,您可以使用awk,这让工作更轻松。
  • 感谢大家的支持,我学到了有关该主题的有用提示。

标签: macos sed


【解决方案1】:

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

sed '/StringToSearch/{n;p;s/[^| ]\+/uk/}' file

匹配包含StringToSearch的行。

打印该行并获取下一行。

打印该行并将uk 替换为isoCode(该行也将作为正常sed 流程的一部分打印)。

请参阅here 进行演示。

【讨论】:

    【解决方案2】:

    使用sed:

    sed -e '/^[[:space:]]*StringToSearch:/{' -e n -e n -e 'i\
    \ \ \ \ | uk |' -e '}' file > outputfile
    

    输出:

    someText
    StringToSearch:
        | isoCode |
        | uk |
    
    someOthertext
    StringToSearch:
        | isoCode |
        | uk |
    
    againSomOtherText
    StringToSearch:
        | isoCode |
        | uk |
    

    这将匹配任何带有可选空格和StringToSearch: 的行,然后-e n -e n 将读取两行并清除模式空间,然后-e 'i\ \ \ \ \ | uk | 将插入您选择的一行,-e '}' 将关闭该块。

    【讨论】:

    • 谢谢,很好的例子
    【解决方案3】:
    sed -E 's,\^\s*StringToSearch:\n\([^\n]+\),| uk |,'
    
    • \(...\) 在常规正则表达式中保存反向引用。在扩展正则表达式中使用(...)。此外,您不要在任何地方使用反向引用。
    • \n - sed一次解析一行。所以它不能匹配\n,除非您使用N 命令将多行附加到模式空间。
    • \^ 很奇怪 - 它匹配 ^ 字符。您的文字中没有这样的字符...

    您可以使用-z 选项轻松地将多行与 GNU sed 匹配。请注意,它将整个文件加载到seds 内存中,因此会消耗内存。然后编写一个适当的正则表达式,它将全局匹配您的表达式。

    同样不要删除替换的字符串,使用& 重新恢复它。然后在它后面加上你要添加的字符串。

    命令:

    $ sed -z -E 's,\nStringToSearch:\n[^\n]+\n,&    | uk |\n,g' <<EOF
    someText
    StringToSearch:
        | isoCode |
    
    someOthertext
    StringToSearch:
        | isoCode |
    
    againSomOtherText
    StringToSearch:
        | isoCode |
    EOF
    

    输出:

    someText
    StringToSearch:
        | isoCode |
        | uk |
    
    someOthertext
    StringToSearch:
        | isoCode |
        | uk |
    
    againSomOtherText
    StringToSearch:
        | isoCode |
        | uk |
    

    【讨论】:

    • 谢谢,很好的例子
    【解决方案4】:
    $ awk '1; p~/StringToSearch/ && /isoCode/{print "    | uk |"} {p=$0}' ip.txt
    someText
    StringToSearch:
        | isoCode |
        | uk |
    
    someOthertext
    StringToSearch:
        | isoCode |
        | uk |
    
    againSomOtherText
    StringToSearch:
        | isoCode |
        | uk |
    
    • 1 打印包含当前记录的 $0 内容的惯用方式
    • {p=$0} 将当前记录保存在 p 变量中
    • p~/StringToSearch/ &amp;&amp; /isoCode/ 这会检查上一行是否包含 StringToSearch 并且当前行是否包含 isoCode
      • 如果条件满足,print " | uk |"会添加你需要的新内容

    据我所知,这应该适用于所有版本的awk。所以mac/linux不会影响你。


    如果你坚持sed,你可以使用

    sed '/StringToSearch/{N; s/$/\n    | uk |/}' ip.txt
    

    我在GNU sed 上测试过,但不确定语法/功能是否会随其他实现而变化。 N 命令将下一行输入添加到当前模式空间。 s/$/\n | uk |/ 将在这两行之后添加新内容。 sed 默认在不使用 -n 选项时打印模式空间。

    【讨论】:

      猜你喜欢
      • 2021-09-12
      • 2013-07-21
      • 2013-04-30
      • 2022-07-21
      • 2010-11-29
      • 2014-06-08
      • 2018-05-02
      • 2017-09-06
      • 1970-01-01
      相关资源
      最近更新 更多