【问题标题】:Strip last part of file by pattern - remove last certificate from chain按模式剥离文件的最后一部分 - 从链中删除最后一个证书
【发布时间】:2020-10-15 17:10:49
【问题描述】:

我有一个这样的 SSL 证书链

-----BEGIN CERTIFICATE-----
MIICPjCCAeSgAwIBAgIRALMMpKnhRM2C7mnKI/rl8ggwCgYIKoZIzj0EAwIwgY4x
CERT1
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDIjCCAsegAwIBAgIOAMjnPM1wShDmOWUELuIwCgYIKoZIzj0EAwIwgagxCzAJ
CERT2
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDIDCCAsWgAwIBAgIOAMjnPL8JUbVSmpMadWUwCgYIKoZIzj0EAwIwbDELMAkG
CERT3
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDBjCCAqygAwIBAgIFFRCCEwYwCgYIKoZIzj0EAwIwgZQxFDASBgNVBAoMC0Ft
CERT4
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDNjCCAtugAwIBAgIJAKpBxYNyH8biMAoGCCqGSM49BAMCMIGUMRQwEgYDVQQK
CERT5
-----END CERTIFICATE-----

我需要从中删除最后一个证书。

在 MacOS/BSD 命令 split 有标志 -p 按模式分割,我使用它:

cat cert | split -p "-----BEGIN CERTIFICATE-----" 
cat xa{a,b,c,d}

我相信在 Linux 上也有一条命令可以在一行中执行此操作,但在 Ubuntu 上,命令 split 无法按模式拆分。

我需要使用标准的 linux 命令来完成这项工作,例如我标记的那些。

【问题讨论】:

    标签: awk sed ack


    【解决方案1】:

    这个 GNU Sed 解决方案应该足够了

    sed -zE 's/(.*\n)-----BEGIN CERTIFICATE-----.*/\1/' your_input
    

    其中-E 允许使用(…) 而不是\(…\) 来捕获某些东西,-z(在 GNU Sed 中可用)将整个输入视为一个嵌入了\ns 的单个长字符串.

    因此,第一个 .* 尽可能匹配(并捕获它,以及紧随其后的 \n,因此它可以使用 \1 在替换中引用它),只要它紧随其后的是\n-----BEGIN CERTIFICATE----- 以及它之后的任何其他内容(第二个.*)。

    【讨论】:

    • 它删除了最后一个-----END CERTIFICATE-----,但它确实有效。谢谢。
    • @kyb,你不想删除它吗?请在您的问题中包含所需的输出。
    • 此命令输出 4 个证书,剥离第 5 个。这就是我要找的。但是第 4 个证书看起来坏了,因为它没有 -----END CERTIFICATE-----。我想在输出中看到 4 个有效证书。 (当然用echo手动添加也很方便)
    • @kyb 我已经修复了它(老实说,根据 Ed 的建议)。基本上我有(.*)\n,它没有捕获,因此删除了EOF的最后一个换行符,这是一些VS编辑器所要求的(VS =非常愚蠢);将其更改为 (.*\n) 会保留捕获组中的最后一个换行符,因此会保留在输出中,从而使那些编辑者满意。
    • 是的。现在它按预期工作。谢谢你。我以前不知道-z
    【解决方案2】:

    使用 GNU awkgensub,您可以尝试仅根据所示示例进行跟踪、编写和测试。

    awk -v RS="" -v regex="(.*)\n(-----BEGIN CERTIFICATE-----.*)" '
    {
      print gensub(regex,"\\1","1",$0)
    }' Input_file
    

    【讨论】:

    • 据我了解 RS="" 用于“slurp 模式”,因此 $0 包含完整的输入文件。对吗?
    • @kyb no,RS=""(或RS='')用于“段落模式”`,其中记录由空行分隔。 RS='^$'(如果您的 awk 版本支持多字符 RS)用于“slurp 模式”,其中 $0 包含完整的输入文件。当输入不包含任何空行(这可能是您的情况)时,它们的行为相似,除了 RS=""$0 将不包含文件中的最后一个换行符,而 RS='\0' 它将包含。要查看差异,请尝试 echo 7 | awk -v RS='' '{print "<" $0 ">"}'echo 7 | awk -v RS='^$' '{print "<" $0 ">"}' 并注意第一个输出中 > 之前的换行符。
    • @EdMorton,谢谢你先生在这里澄清对不起我的理解是错误的。
    【解决方案3】:

    单独使用任何 awk:

    $ awk '/-----BEGIN CERTIFICATE-----/{printf "%s", rec; rec=""} {rec=rec $0 ORS}' file
    -----BEGIN CERTIFICATE-----
    MIICPjCCAeSgAwIBAgIRALMMpKnhRM2C7mnKI/rl8ggwCgYIKoZIzj0EAwIwgY4x
    CERT1
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    MIIDIjCCAsegAwIBAgIOAMjnPM1wShDmOWUELuIwCgYIKoZIzj0EAwIwgagxCzAJ
    CERT2
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    MIIDIDCCAsWgAwIBAgIOAMjnPL8JUbVSmpMadWUwCgYIKoZIzj0EAwIwbDELMAkG
    CERT3
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    MIIDBjCCAqygAwIBAgIFFRCCEwYwCgYIKoZIzj0EAwIwgZQxFDASBgNVBAoMC0Ft
    CERT4
    -----END CERTIFICATE-----
    

    或者如果你有tac:

    $ tac file | awk 'f; /-----BEGIN CERTIFICATE-----/{f=1}' | tac
    -----BEGIN CERTIFICATE-----
    MIICPjCCAeSgAwIBAgIRALMMpKnhRM2C7mnKI/rl8ggwCgYIKoZIzj0EAwIwgY4x
    CERT1
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    MIIDIjCCAsegAwIBAgIOAMjnPM1wShDmOWUELuIwCgYIKoZIzj0EAwIwgagxCzAJ
    CERT2
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    MIIDIDCCAsWgAwIBAgIOAMjnPL8JUbVSmpMadWUwCgYIKoZIzj0EAwIwbDELMAkG
    CERT3
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    MIIDBjCCAqygAwIBAgIFFRCCEwYwCgYIKoZIzj0EAwIwgZQxFDASBgNVBAoMC0Ft
    CERT4
    -----END CERTIFICATE-----
    

    【讨论】:

    • 您知道 OP 对此输出抱怨什么吗? (请参阅他们在我的问题下的评论。)
    • @Enrico 我怀疑他们正在使用编辑器或其他工具来验证丢弃/隐藏输出最后一行的输出,因为它没有以换行符结尾(我知道你现在修复了),所以对他们来说,最后的 END 行丢失了。
    • 呜呜呜,我以为他们指的是原始的最后一行!他们显然指的是您在我的代码中更正的错误。那么再次感谢。
    • 不客气。我只是猜测这当然是它的内容,但它似乎很可能,我想不出其他任何东西!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多