我有以下 XML 片段:
<value id="1" creatorId="0" creationTime="1639487132" expirationTime="1639573532">+380554446363</value>
<value id="1" creatorId="0" creationTime="1639487132" expirationTime="1639573532">+380554446364</value>
<value id="1" creatorId="0" creationTime="1639487132" expirationTime="1639573532">+380554446365</value>
我尝试<value>
使用以下命令将标签内容替换为其 SHA-1 哈希值:
cat test.xml | sed "s/>[+]\([0-9][0-9]*\)<\/value>/>+$(echo \\1 | sha1sum | cut -f1 -d' ')<\/value>/g"
它会失败,因为用相同的错误值替换所有找到的案例。
预期的:
<value id="1" creatorId="0" creationTime="1639487132" expirationTime="1639573532">34df370575e3528b31daef8633cb539119a3b028</value>
<value id="1" creatorId="0" creationTime="1639487132" expirationTime="1639573532">d93767c769fd51bcf9eb25f95932559b24bae812</value>
<value id="1" creatorId="0" creationTime="1639487132" expirationTime="1639573532">20338c1f048bed553b6cce76eaf1d388ba7686f5</value>
得到:
<value id="1" creatorId="0" creationTime="1639487132" expirationTime="1639573532">+cbcac786fef5abeb39fe473ab6abe554978a8156</value>
<value id="1" creatorId="0" creationTime="1639487132" expirationTime="1639573532">+cbcac786fef5abeb39fe473ab6abe554978a8156</value>
<value id="1" creatorId="0" creationTime="1639487132" expirationTime="1639573532">+cbcac786fef5abeb39fe473ab6abe554978a8156</value>
我可能做错了什么? TIA。
答案1
不要使用sed
或编辑 XML awk
。使用适当的xml
解析器,例如 python 的xml.etree
:
input.xml
:
<values>
<value id="1" creatorId="0" creationTime="1639487132" expirationTime="1639573532">+380554446363</value>
<value id="1" creatorId="0" creationTime="1639487132" expirationTime="1639573532">+380554446364</value>
<value id="1" creatorId="0" creationTime="1639487132" expirationTime="1639573532">+380554446365</value>
</values>
#!/usr/bin/env python3
import hashlib
import xml.etree.ElementTree as ET
tree = ET.parse('input.xml')
root = tree.getroot()
for value in root:
value.text = hashlib.sha256(value.text.encode('utf-8')).hexdigest()
tree.write('output.xml')
output.xml
:
<values>
<value id="1" creatorId="0" creationTime="1639487132" expirationTime="1639573532">4b2bdff20d17dc4ae7ad99937399530b39bd7a63f7348375c547d01565c11898</value>
<value id="1" creatorId="0" creationTime="1639487132" expirationTime="1639573532">8d3b1452d83ef803f8043eaddbe2fc58b0fd42c8ad5abc554e78796548f75ddb</value>
<value id="1" creatorId="0" creationTime="1639487132" expirationTime="1639573532">06bd986417875e536401306180c51b7ded4eeab179933e0026a103bc8dc9eee7</value>
</values>
答案2
正在sha1sum
评估常量字符串“\\1”的 SHA-1,而不是第一个 SED 正则表达式匹配:
$ echo \\1 | sha1sum
cbcac786fef5abeb39fe473ab6abe554978a8156 -
shell 在执行命令(在本例中为 sed)之前执行所有各种扩展(例如命令替换)。因此,shell 展开
cat test.xml | sed "s/>[+]\([0-9][0-9]*\)<\/value>/>+$(echo \\1 | sha1sum | cut -f1 -d' ')<\/value>/g"
到
cat test.xml | sed "s/>[+]\([0-9][0-9]*\)<\/value>/>+cbcac786fef5abeb39fe473ab6abe554978a8156<\/value>/g"
然后它运行两个进程,一个正在运行
cat test.xml
另一个正在运行
sed "s/>[+]\([0-9][0-9]*\)<\/value>/>+cbcac786fef5abeb39fe473ab6abe554978a8156<\/value>/g"
第一个进程的 STDOUT 通过管道传输到第二个进程的 STDIN。
为了使您想要做的事情发挥作用,sed
必须能够从 内部执行其他可执行文件sed
。我不相信sed
可以做到这一点,所以你必须以其他方式做到这一点。
您可以使用 来完成此操作sed
,例如这是一种方法
for a in `cat test.xml | sed -E 's,^.*>(\+[0-9]+)<\/value>$,\1,'`; do echo "$a" | sha1sum | cut -f1 -d' '; done >2nd
cat test.xml | sed -E 's,>\+[0-9]+</value>$,>,' >1st
paste -d '' 1st 2nd | sed -E 's,$,</value>,'
您也没有在第一个匹配字符串的括号中包含“+” sed
,根据您作为预期结果提供的 SHA1 和,我相信您希望包含“+”,所以我也更正了这一点。
答案3
GNU sed 替换命令有一个/e
修饰符,它作为 vash 代码执行,即 s/// 的 rhs,又名修改后的模式空间。
sed -E "
s/'/&\\\\&&/g
s:(<.*>)([+][0-9]+)(</value>.*):printf '%s%s%s' '\\1' \"\$(echo '\\2'|sha1sum|cut -d' ' -f1)\" '\\3':e
" test.xml
<value id="1" creatorId="0" creationTime="1639487132" expirationTime="1639573532">34df370575e3528b31daef8633cb539119a3b028</value>
<value id="1" creatorId="0" creationTime="1639487132" expirationTime="1639573532">d93767c769fd51bcf9eb25f95932559b24bae812</value>
<value id="1" creatorId="0" creationTime="1639487132" expirationTime="1639573532">20338c1f048bed553b6cce76eaf1d388ba7686f5</value>
答案4
如果您使用的系统具有xmlstarlet编译为crypto
扩大你可以说的功能:
xmlstarlet sel -N crypto='http://exslt.org/crypto' \
-t -m '//value' -e '{name()}' -c '@*' -v 'crypto:sha1(.)' -b -n \
file.xml
输出:
<value id="1" creatorId="0" creationTime="1639487132" expirationTime="1639573532">3bacaac1e104d7bfde5ff462d461d3b4b917c037</value>
<value id="1" creatorId="0" creationTime="1639487132" expirationTime="1639573532">808b3e7bb8c8c7c06c328a082bac64205837531b</value>
<value id="1" creatorId="0" creationTime="1639487132" expirationTime="1639573532">8c31811a3b8d816f719ad5c78b58810b9b6cd4b7</value>
其中校验和与所需的输出不同,因为它们不是根据包括换行符的文本计算的。
xmlstarlet transform --show-ext 2>&1 | grep crypto
在我的最终输出中运行:
{http://exslt.org/crypto}md4
{http://exslt.org/crypto}sha1
{http://exslt.org/crypto}md5
{http://exslt.org/crypto}rc4_decrypt
{http://exslt.org/crypto}rc4_encrypt