首页 > 解决方案 > 替换bash中多行的值

问题描述

即使使用 stackoverflow 和 google 上的所有示例,我也很挣扎。

基本上我有以下文字

    /start r.start ""
      GAIN 0x256 __POSITIVE 1 FOO
      OTHER
      OTHER
      /start MACRO
        200
        CODE "r.start" 0x256 0x2 10 0xA3
      /end MACRO
      OTHER
    /end

我需要通读这个文件,搜索作为 $1 传递的名称 egrstart 并用我作为 $2 传递的值替换例如 0x256。有两个实例可以替换,第 2 行和第 7 行。

我知道的事情:

  1. /start 前面有 4 个空格
  2. GAIN 前面有 6 个空格
  3. \r\n 或 \n 可能存在
  4. CODE 前面有 8 个空格

直到现在我已经达到了这一点

pattern="N;s\s\/start r.start \"\"\n      GAIN 0x\(.*\)"
replacement"\/start r.start \"\"\n      GAIN 0x82"
sed -e "$pattern/$replacement/p" test.txt

但我什么也没得到。我也可以替换第一行,但无论出于何种原因,它都将我的前两行粘贴了两次

假设以下调用的期望值

./run.sh r.start 0x284569

应该

    /start r.start ""
      GAIN 0x284569 __POSITIVE 1 FOO
      OTHER
      OTHER
      /start MACRO
        200
        CODE "r.start" 0x284569 0x2 10 0xA3
      /end MACRO
      OTHER
    /end

这是我第二部分的最佳镜头

var="r.start"
val="0x48209F82"

pattern="\(CODE \"$var\" \).*\(.*\)"
replacement="\1$val\2"
sed "s/$pattern/$replacement/g" test.txt

问题是它在值替换后删除了所有内容。我不能输入 \2 以下字符

编辑:

通过执行以下操作

var="r.start"
val="0x48209F82"

pattern="\(CODE \"$var\" \).*\(\s.*\s.*\s.*\)"
replacement="\1$val\2"
sed "s/$pattern/$replacement/g" test.txt

我得到了我想要的,但感觉有点脏,如果字符数量可变,我如何减少最后一部分?我可以以某种方式匹配所有内容直到行尾吗?

标签: regexbashawksedgrep

解决方案


像下面这样的东西怎么样?它使用sed范围来选择/startand之间的所有内容/end,并在范围内使用块来替换与GAINand匹配的行的值CODE

$ cat foo.txt
    /start r.start ""
      GAIN 0x256 __POSITIVE 1 FOO
      OTHER
      OTHER
      /start MACRO
        200
        CODE "r.start" 0x256 0x2 10 0xA3
      /end MACRO
      OTHER
    /end
$ sed '\#/start r\.start#,\#/end#{/\(GAIN\|CODE "r\.start"\)/s/0x[a-fA-F0-9]\+/0x284569/}' foo.txt
    /start r.start ""
      GAIN 0x284569 __POSITIVE 1 FOO
      OTHER
      OTHER
      /start MACRO
        200
        CODE "r.start" 0x284569 0x2 10 0xA3
      /end MACRO
      OTHER
    /end

格式化后的sed脚本如下所示:

\#/start r\.start#,\#/end# {
    /\(GAIN\|CODE "r\.start"\)/s/0x[a-fA-F0-9]\+/0x284569/
}

笔记

  • 使用范围模式\#...#代替而不是/.../,所以我们不必引用斜杠
  • 仅用于替换包含的/patten1/s/pattern2/string/pattern2pattern1
  • 使用{...}块,以便替换仅适用于/start和之间/end

您可以像这样参数化模式和值:

#!/bin/bash

var='r\.start'
val='0x48209F82'

sed '\#/start '$var'#,\#/end#{/\(GAIN\|CODE "'$var'"\)/s/0x[0-9a-fA-F]\+/'$val'/}' foo.txt

推荐阅读