【问题标题】:replace multiline text between xml tags with awk用awk替换xml标签之间的多行文本
【发布时间】:2018-04-30 21:01:15
【问题描述】:

我有一个 xml 文件

`<private-keys>
    <private-key>
        <name>ssh_host_rsa_key</name>
    </private-key>
    <private-key>
        <name>test_server_pvt_key</name>
        <certificate-chains>
            <certificate-chain>
                <name>server_cert</name>
         <certificate>MIIECTCCAvGgAwIBAgIBCDANBgkqhkiG9w0BAQsFADCBjDELMAkGA1UEBhMCQ1ox
FjAUBgNVBAgMDVNvdXRoIE1vcmF2aWExDTALBgNVBAcMBEJybm8xDzANBgNVBAoM
...
J1t4nk9saeo87kIuNEDfYNdwYZzRfXoGJ5qIJQK+uJJv9noaIhfFowDW/G14Ji5p
Vh/YtvnOPh7aBjOj8jmzk8MqzK+TZgT7GWu48Nd/NaV8g/DNg9hlN047LaNsJly3
NX3+VBlpMnA4rKwl1OnmYSirIVh9RJqNwqe6k/k=</certificate>
            </certificate-chain>
        </certificate-chains>
    </private-key>
</private-keys>`

我正在尝试提出一个 awk 或 sed 可用于将多行证书数据&lt;certificate&gt;...multi line data to be replace...&lt;/certificate&gt;替换为另一个多行数据块,结果将类似于:

`<private-keys>
    <private-key>
        <name>ssh_host_rsa_key</name>
    </private-key>
    <private-key>
        <name>test_server_pvt_key</name>
        <certificate-chains>
            <certificate-chain>
                <name>server_cert</name>
     <certificate>MIIEpAIBAAKCAQEAueCQaNQWoNmFK6LKu1p8U8ZWdWg/PvDdLsJyzfzl/Qw4UA68
SfFNaY06zZl8QB9W02nr5kWeeMY0VA3adrPgOlvfx3oWlFbkETnMaN4OT3WTQ0Wt
6jAWZDzVfopwpJPAzRPxACDftIqFGagYcF32hZlVNqqnVdbXh0S0EViweqp/dbG4
...
B4f09aeELM2ASIuk8Q/Mx0jQFnm8lzRFXdewgvdPoZW/7VufM9O7dGPOc41cm2Dh
yrTcXx/VmUBb+/fnXVEgCv7gylp/wtdTGHQBQJHR81jFBz0lnLj+gg==</certificate>
            </certificate-chain>
        </certificate-chains>
    </private-key>
</private-keys>`

我没有任何高级正则表达式实用程序,只有 linux shell(甚至没有 bash)awk 和 sed 是可用的工具。

【问题讨论】:

  • 你能安装任何库/包吗?
  • 我建议使用 XML/HTML 解析器(例如 xmlstarlet)。
  • 很遗憾,我无法在目标上安装任何东西。

标签: awk


【解决方案1】:
$ cat tst.awk
NR==FNR {
    cert = (NR==1 ? "" : cert ORS) $0
    next
}
sub(/<certificate>.*/,"") {
    beg = $0 "<certificate>"
    inCert = 1
}
inCert {
    if ( sub(/.*<[\/]certificate>/,"") ) {
        end = "</certificate>" $0
        print beg cert end
        inCert = 0
    }
    next
}
{ print }

.

$ cat repl
MIIEpAIBAAKCAQEAueCQaNQWoNmFK6LKu1p8U8ZWdWg/PvDdLsJyzfzl/Qw4UA68
SfFNaY06zZl8QB9W02nr5kWeeMY0VA3adrPgOlvfx3oWlFbkETnMaN4OT3WTQ0Wt
6jAWZDzVfopwpJPAzRPxACDftIqFGagYcF32hZlVNqqnVdbXh0S0EViweqp/dbG4
...
B4f09aeELM2ASIuk8Q/Mx0jQFnm8lzRFXdewgvdPoZW/7VufM9O7dGPOc41cm2Dh
yrTcXx/VmUBb+/fnXVEgCv7gylp/wtdTGHQBQJHR81jFBz0lnLj+gg==

.

$ awk -f tst.awk repl file
<private-keys>
    <private-key>
        <name>ssh_host_rsa_key</name>
    </private-key>
    <private-key>
        <name>test_server_pvt_key</name>
        <certificate-chains>
            <certificate-chain>
                <name>server_cert</name>
         <certificate>MIIEpAIBAAKCAQEAueCQaNQWoNmFK6LKu1p8U8ZWdWg/PvDdLsJyzfzl/Qw4UA68
SfFNaY06zZl8QB9W02nr5kWeeMY0VA3adrPgOlvfx3oWlFbkETnMaN4OT3WTQ0Wt
6jAWZDzVfopwpJPAzRPxACDftIqFGagYcF32hZlVNqqnVdbXh0S0EViweqp/dbG4
...
B4f09aeELM2ASIuk8Q/Mx0jQFnm8lzRFXdewgvdPoZW/7VufM9O7dGPOc41cm2Dh
yrTcXx/VmUBb+/fnXVEgCv7gylp/wtdTGHQBQJHR81jFBz0lnLj+gg==</certificate>
            </certificate-chain>
        </certificate-chains>
    </private-key>
</private-keys>

【讨论】:

  • 谢谢,这可以完美地在桌面上运行(我猜是傻瓜)。但是在busybox awk上给了我一个错误'awk: bad regex'.*
  • @EdMorton 它确实不适用于旧的busybox 版本的awk。将/.*&lt;[/]certificate&gt;/ 替换为/.*&lt;.certificate&gt;,它将起作用(仅在这种情况下)。
  • 抱歉,您需要转义括号表达式中的反斜杠,以便移植到所有 awks。将 /[/]/ 更改为 /[\/]/。我已经更新了答案中的脚本。
  • @EdMorton 谢谢。这是有效的。还有一个问题,我们如何过滤替换只发生在带有&lt;name&gt;server_cert&lt;/name&gt; 的证书名称中。这是我忽略的一点,awk脚本替换了所有的证书,我只想替换server_cert的证书。
  • 不客气。我不确定我理解你的意思,发布一个新问题,并附上它自己的示例输入和预期输出以及明确说明的要求。
猜你喜欢
  • 2017-10-07
  • 2012-09-01
  • 2021-07-21
  • 1970-01-01
  • 1970-01-01
  • 2015-11-19
  • 1970-01-01
  • 2016-03-29
  • 1970-01-01
相关资源
最近更新 更多