代码之家  ›  专栏  ›  技术社区  ›  Gábor Lipták

Linux shell:base64解码,删除换行符

  •  1
  • Gábor Lipták  · 技术社区  · 6 年前

    我有一个文件,其中每一行都是base64编码的XML文档。解码的XML文档可能包含新行字符。我想对每个包含给定单词的XML文档进行grep。

    问题是,当我对文件的行进行解码时,每个base64编码的行有多行,我不能再对其进行grep。我需要类似的东西 base64 decode + remove line breaks 一步一步。

    如何在Linux shell中实现这一点?我有python、perl和awk。

    >cat fileContainingBase64EncodedXMLsInEachLine.txt | what should I write here?
    

    输入:

    PGZvbz4NCjxiYXIvPg0KPC9mb28+
    PGZvbz4NCjxodWh1Lz4NCjwvZm9vPg==
    PGZvbz4NCjxiYXJvbWV0ZXIvPg0KPC9mb28+
    

    预期产量

    假设我想要包含“bar”的XML文档

    <foo>
    <bar/>
    </foo>
    <foo>
    <barometer/>
    </foo>
    

    我的问题的一个例子

    >cat fileContainingBase64EncodedXMLsInEachLine.txt | base64 --decode | grep bar
    

    提供:

    <bar/>
    <barometer/>
    

    所以我没有包含 bar barometer .

    5 回复  |  直到 6 年前
        1
  •  2
  •   PM 2Ring    6 年前

    下面是一些python代码,它接受一个文件名,后跟命令行上的搜索词。和往常一样,如果其中一个参数包含空格,则必须对其进行引用。

    import sys
    from base64 import b64decode
    
    fname, pattern = sys.argv[1:]
    with open(fname) as f:
        for row in f:
            row = b64decode(row).decode()
            if pattern in row:
                print(row, end='\n\n')
    

    在您的数据上运行这个命令,并使用模式arg中的“bar”命令:

    <foo>
    <bar/>
    </foo>
    
    <foo>
    <barometer/>
    </foo>
    

    为了练习我相当生疏的awk技巧,我决定编写一个awk命令行来完成这项工作。它使用标准 base64 命令进行解码。

    awk 'BEGIN{cmd="base64 -d"}; {print |& cmd; close(cmd,"to"); z=""; while(cmd |& getline s) z=z s "\n"; close(cmd); if (z~pat)print z}' pat='bar' testdata_b64.txt
    

    你用 pat 参数,可以是正则表达式。您可以通过标准输入向它发送数据,也可以在命令行中为它指定一个或多个文件名。

    请注意,regex模式需要双重转义,例如 pat='\\<bar\\>' 与单词匹配 bar .

        2
  •  1
  •   kvantour    6 年前

    更新: 如果您知道第一个节点名是 <foo> ,然后您可以执行以下操作:

    $ echo "<head>$(base -decode <file>)</head>" | \
      xmlstarlet sel -t -m '//bar/ancestor::foo' -c .
    

    它选择名为 foo 调用的节点的 bar ,自 是第一个XML节点,它将选择请求的XML文件。

    原始答案如下:

    使用 xmlstarlet 你可能想这样做

    $ echo "<head>$(base -decode <file>)</head>" | \
      xmlstarlet sel -t -m '//bar/ancestor::*[last()-1]' -c .
    

    这从本质上选择了节点“bar”的祖先的完整XML树,但它只会达到正确的深度。

    我加了一个额外的 head 使完整字符串成为有效的 xml 文件。这样,您只需要从第一个节点开始打印。

    这个 echo 会产生类似(稍微不同的版本):

    <head> 
      <foo /> 
      <foo> 
        <barometer /> 
      </foo> 
      <foo> 
        <DDD> 
          <BBB/> 
          <bar /> 
        </DDD> 
      </foo> 
    </head>
    

    XMLStarlet 将根据xpath进行模板选择 //bar/ancestor::* ,导致以下一组匹配

    • <bar />
    • <DDD><BBB /><bar /></DDD>
    • <foo><DDD><BBB /><bar /></DDD></foo>
    • <head> everything </ head>

    我们对倒数第二个感兴趣,即 [last()-1] 我们要求打印一份 -c .

        3
  •  1
  •   Kjetil S.    6 年前

    Perl去营救:

    perl -MMIME::Base64 -nE '$_=decode_base64($_);/bar/&&say' fileContaining...txt
    

    cat fileContaining...txt | perl -MMIME::Base64 -nE'$_=decode_base64($_);/bar/&&say'
    
        4
  •  0
  •   Zapho Oxx    6 年前

    您可以尝试下面的python脚本。它不是命令行onliner,但这应该给你想要的。使用方法:

    >python3 get_xml.py SEARCHSTRING FILENAME
    

    例如,输出为:

    <foo>
    <bar/>
    </foo>
    <foo>
    <barometer/>
    </foo>
    

    脚本:

    import base64
    import sys
    script_name = sys.argv[0]
    search_string = sys.argv[1]
    filename = sys.argv[2]
    print("[+] ({}) search for {}".format(script_name,search_string,filename))
    with open(filename,"r") as xml_in:
        nextline = xml_in.readline()
        while nextline != '':
            xml = base64.b64decode(nextline).decode("utf-8").rstrip()
            if search_string in xml:
                print(xml)
            nextline = xml_in.readline()
    
        5
  •  0
  •   martin_joerg    6 年前

    你可以用 tr 在循环中删除每个XML文档的所有新行,如下所示:

    #!/bin/bash
    
    while IFS='' read -r line
    do
        echo -n "$line" | base64 --decode | tr -d '\r\n'
        echo
    done < fileContainingBase64EncodedXMLsInEachLine.txt