【问题标题】:Find multi-line text & replace it, using regex, in shell script在 shell 脚本中使用正则表达式查找多行文本并替换它
【发布时间】:2021-05-08 05:16:26
【问题描述】:

我正在尝试查找两个连续行的模式,其中第一行是固定字符串,第二行是我喜欢替换的部分子字符串。

这将在 macOS 上的 sh 或 bash 中完成。

如果我手头有一个可以对整个文本进行操作的正则表达式工具,这对我来说会很容易。但是,我发现的只是 bash 的简单文本替换 - 不适用于正则表达式,以及面向行的 sed。

我怀疑我可以使用sed 的方式,它首先找到匹配的第一行,然后如果它的模式也匹配,然后才寻找替换下一行,但我无法弄清楚。

或者 macOS 上是否有其他工具可以让我对整个文件或字符串进行基于正则表达式的搜索和替换?也许用 Python(安装了 v2.7 和 v3)?

这是一个示例文本以及我喜欢它的修改方式:

  keyA
  value:474
  keyB
  value:474    <-- only this shall be replaced (follows "keyB")
  keyC
  value:474
  keyB
  value:474

现在,我想查找第一行是“keyB”且下一行是“value:474”的所有出现,然后将第二行替换为另一个值,例如“价值:888”。

作为一个忽略行分隔符的正则表达式,我会这样写:

  • 搜索:(\bkeyB\n\s*value):474
  • 替换:$1:888

所以,基本上,我找到 474 之前的模式,然后用相同的模式加上新的数字 888 替换它,从而保留原始缩进(可变)。

【问题讨论】:

  • 试试sed '/keyB$/{n;s/\(.*\):[0-9]*/\1:888/}' file或sed -e '/keyB$/{n' -e 's/\(.*\):[0-9]*/\1:888/' -e '}' file

标签: regex bash shell sed sh


【解决方案1】:

使用带有-0777 的 perl 单行代码来扫描多行:

$ # inline edit:
$ perl -0777 -i -pe 's/\bkeyB\s*value):\d*/$1:888/' file.txt
$ # to stdout:
$ cat file.txt | perl -0777 -pe 's/\bkeyB\s*value):\d*/$1:888/'

【讨论】:

  • 啊,Perl。我长期回避的克星 :) “-0777”是干什么用的?不是权限,是吗?
  • -0777 将行分隔符更改为undef,以便一次性将所有行提供给 perl。
【解决方案2】:

你可以使用

sed -e '/keyB$/{n' -e 's/\(.*\):[0-9]*/\1:888/' -e '}' file
# Or, to replace the contents of the file inline in FreeBSD sed:
sed -i '' -e '/keyB$/{n' -e 's/\(.*\):[0-9]*/\1:888/' -e '}' file

详情:

  • /keyB$/ - 查找所有以 keyB 结尾的行
  • n - 清空当前模式空间并将下一行读入其中
  • s/\(.*\):[0-9]*/\1:888/ - 查找直到最后一个 : + 零个或多个数字将该文本捕获到第 1 组的任何文本,并替换为该组的内容和 :888。

{...} 创建一个仅在满足/keyB$/ 条件时执行的块。

查看online sed demo。

【讨论】:

  • 虽然 Perl 解决方案更直接地根据我自己的技能为我提供了我想做的事情,但我很高兴能更多地了解sed 及其对连续行的处理。
【解决方案3】:

在普通的 bash 中:

#!/bin/bash

keypattern='^[[:blank:]]*keyB$'
valpattern='(.*):'
replacement=888

while read -r; do
    printf '%s\n' "$REPLY"
    if [[ $REPLY =~ $keypattern ]]; then
        read -r
        if [[ $REPLY =~ $valpattern ]]; then
            printf '%s%s\n' "${BASH_REMATCH[0]}" "$replacement"
        else
            printf '%s\n' "$REPLY"
        fi
    fi
done < file

【讨论】:

    猜你喜欢
    • 2019-11-06
    • 1970-01-01
    • 2019-02-10
    • 1970-01-01
    • 1970-01-01
    • 2022-01-13
    • 2016-02-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多