在 shell 脚本中使用正则表达式查找多行文本并替换它

问题描述 投票:0回答:4

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

这需要在 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 替换它,从而保留原始缩进(这是可变的)。

regex bash shell sed sh
4个回答
5
投票

你可以使用

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$/
条件后执行。

查看在线

sed
演示


2
投票

使用带有

-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/'

1
投票

简单的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

0
投票

这是一个 Bash 脚本,使用 行编辑器 自动替换/更新文本文件中多行文本的一部分 生成的内容(例如:目录)👇

替换.sh

#!/usr/bin/env bash
# -*- coding: UTF-8 -*-
#
# github   : https://github.com/JV-conseil
# www      : https://www.jv-conseil.net
# author   : JV-conseil
#===============================================

_lines=""

for i in {1..10}; do
  _lines+=$'\n'"${i}. ""$(openssl rand -hex 12)"
done

ed -s "./sample.md" <<EOF
/## BEGIN GENERATED/+,/## END GENERATED/-d
/## BEGIN GENERATED/a
${_lines}

.
wq
EOF

样本.md

# How to replace part of a text file between markers with another text file?

Here is a Bash script using [ed line editor](https://www.gnu.org/software/ed/manual/ed_manual.html "GNU manual for ed line editor") to replace / update a part of multiline text in a text file with
automatically generated content (eg: Table of contents) 👇

## BEGIN GENERATED

1. d5c10e45943b196b005771f1
2. bc56de530fbf5342d55203b4
3. 9608f31a09c2ece9c9cee4dd
4. 54e361257aecce0a937211c0
5. c4b2edf88293df0747694c37
6. a80275accc9b2bc72d55efcd
7. 3a2e2fec5da23b415569de00
8. 524655319a05e7dd1f48e6a5
9. 879d17e9e611d163e5a85b02
10. 80d311a786efcd9d01da86f6

## END GENERATED

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris et libero eu nunc
dapibus volutpat. Proin eu neque eu orci volutpat bibendum...
© www.soinside.com 2019 - 2024. All rights reserved.