【问题标题】:Replace multiple lines from a file with mutiple lines from another用来自另一个文件的多行替换文件中的多行
【发布时间】:2014-02-03 18:49:47
【问题描述】:

我可以在几个命令中搜索和替换文件中的多行吗?

我正在尝试用来自dhcp_secondary 的唯一故障转移块替换来自dhcp_primary 的3 个故障转移块,在dhcp_primary 内。

我的目标是将 dhcpd.conf 从主 dhcp 复制到辅助 dhcp(更多信息在这里:http://www.madboa.com/geek/dhcp-failover/)。故障转移只有在配置相同的情况下才能工作,当然除了故障转移块;如您所见,是该网站的示例。 所以我想复制这个文件,但保留辅助节点的故障转移信息。

例如dhcp_primary:

// some lines above
failover peer "A" {
...
}
failover peer "B" {
...
}
failover peer "C" {
...
}
// some lines below

例如dhcp_secondary:

// some different lines above
failover peer "D" {
...
}
// some different lines below

预期的输出必须是:

// some lines above
failover peer "D" {
...
}
// some lines below

我已经可以提取故障转移块了:

awk '/^failover/,/^}$/' dhcp_a

awk '/^failover/,/^}$/' dhcp_b

但我不知道如何继续。

提前致谢。

编辑:我的目标的更多细节。

【问题讨论】:

  • 我不熟悉故障转移块。数字111222 的用途是什么? dhcp_adhcp_b 是两个单独的文件,还是在同一个文件中块?
  • 这里,数字 111 和 222 代表替换一些行。故障转移块一个在另一个之下,中间没有任何线,但是这些块上方有一些线,这些块下方有一些线。而dhcp_a和dhcp_b是分开文件的。
  • 在给定的故障转移块中可以有嵌套的大括号吗?喜欢failover peer "D" { ... subnet { ... } }?辅助故障转移块在主文件中的位置是否任意? (例如,你能把它放在文件的开头吗?)
  • 永远不要在 awk 中使用像 '/a/,/b/' 这样的范围,因为它们使琐碎的解决方案稍微简单一些,但是当它变得稍微复杂一些时,就需要完全重写。只需改用'/a/{f=1} f; /b/{f=0}',然后您就可以完全控制要打印的终止行、需要测试的其他条件,并且您最终不必重新测试相同的条件(a '/a/,/b/' 方法的常见问题)。例如,不打印终止匹配行 - '/a/,/b/{ if (!/b/) print }' vs '/a/{f=1} /b/{f=0} f'.
  • @EdMorton 是的,我也刚刚发现范围表达式不是很灵活..

标签: search replace sed awk lines


【解决方案1】:

你可以试试:

awk -f a.awk dhcp_b dhcp_a

a.awk 在哪里:

/^failover/,/^}$/{
    if (NR==FNR) {
        blk=blk $0 RS
        next
    }
    if (++i==1) {
        printf "%s",blk
    }
    next
}
NR!=FNR{  print }

【讨论】:

  • +1 这可能是我第一次看到/a/,/b/ 有用! nit-pick - NR!=FNR{ print } 可以缩写为 NR!=FNR
  • @EdMorton 谢谢,我只是想我应该尝试使用 OP 中使用范围表达式的代码.. 但我很快发现它确实不是很灵活..
【解决方案2】:

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

sed -n '/^failover peer/,/^}/p' dhcp_b | 
sed -e '/^failover peer/,/^}/!b;r /dev/stdin' -e 'd' dhcp_a

【讨论】:

  • 我对这个命令有一些问题: - b:找不到事件。 - sed: 1: "/^failover peer/,/^}/r ...": 命令 r 最多需要 1 个地址,发现 2 我在 freeBSD 下,很抱歉忘记了这些信息。
  • @Jeelo /dev/stdin 是 GNU 特定的。但是我认为您没有复制解决方案,因为 /.../!b 消除了 r 命令接受 2 个地址的问题。
【解决方案3】:

如果文件只是这种结构和内容类型

NewFile=./FileName

head -1 dhcp_a > ${NewFile}
sed -n '1!{$!p;};}' dhcp_b >> ${NewFile}
tail -1 dhcp_a >> ${NewFile}

只取 dhcp_a 的头部和尾部,并阻止 dhcp_b 的内容

如果文件更大(周围的内容),则使用 /failover/,/}/ 之类的东西作为 sed 中的块分隔符,但这取决于实际内容

【讨论】:

  • 周围的内容比较大,但是不知道怎么在sed中这样使用块分隔符。
  • 提供一个文件样本(如果足够的话,提供一部分)足以估计一个不锚定在文件其他部分的分隔符
  • 这里有一个文件示例:madboa.com/geek/dhcp-failover 在“配置主要”和“配置次要”下我的目标是将 dhcpd.conf 从主要复制到次要。这样,文件配置将是相同的,但我必须保留故障转移块。
【解决方案4】:
$ cat tst.awk
/^failover/ { inRec  = 1 }

{
    if (NR == FNR) {
        if (inRec) {
            rec = rec $0 ORS
        }
    }
    else {
        if (inRec) {
            printf "%s", rec
            rec = ""
        }
        else {
            print
        }
    }
}

/^}/ { inRec = 0 }

$ awk -f tst.awk secondary primary
// some lines above
failover peer "D" {
...
}
// some lines below

【讨论】:

  • 这个解决方案也很好用。感谢 Ed Morton 的帮助。
猜你喜欢
  • 2016-11-20
  • 2019-07-19
  • 2021-04-26
  • 2023-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-08
相关资源
最近更新 更多