我有一个文件,其中每一行都是base64编码的XML文档。解码的XML文档可能包含新的行字符。我想grep出每个包含给定单词的XML文档。
问题在于,当我解码文件的行时,每个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
的完整xml文档。
答案 0 :(得分:2)
这是一些Python代码,它接受命令行上的搜索词后面的文件名。像往常一样,如果arg包含空格,则必须引用它。
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')
使用“bar”在数据上运行此作为模式arg给出:
<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
参数传递模式,该参数可以是正则表达式。您可以通过标准输入向其发送数据,也可以在命令行上为其指定一个或多个文件名。
请注意,正则表达式模式需要双重转义,例如pat='\\<bar\\>'
匹配单词bar
。
答案 1 :(得分:1)
更新:如果您知道第一个节点名称是<foo>
,那么您可以这样做:
$ echo "<head>$(base -decode <file>)</head>" | \
xmlstarlet sel -t -m '//bar/ancestor::foo' -c .
它选择名为foo
的名为bar
的祖先,因为foo
是第一个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 .
答案 2 :(得分:1)
Perl救援:
perl -MMIME::Base64 -nE '$_=decode_base64($_);/bar/&&say' fileContaining...txt
或
cat fileContaining...txt | perl -MMIME::Base64 -nE'$_=decode_base64($_);/bar/&&say'
答案 3 :(得分:0)
您可以尝试以下python脚本。它不是一个命令行在线人,但这应该给你你想要的。用法:
>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()
答案 4 :(得分:0)
您可以在循环中使用tr
删除每个XML文档的所有新行,如下所示:
#!/bin/bash
while IFS='' read -r line
do
echo -n "$line" | base64 --decode | tr -d '\r\n'
echo
done < fileContainingBase64EncodedXMLsInEachLine.txt