bash从元素中提取多个属性值-XML

时间:2019-02-07 14:42:25

标签: xml bash awk

我有一个包含多个元素的XML文件。我想为每个包元素提取特定属性:代码路径,名称和nativelibarypath。

该系统非常基础,并且具有bash,awk,grep等有限的基本linux终端。没有可用的额外软件包,例如xmllint等。因此,我们需要处理的只是bash,awk,sed和grep。

我想在脚本中为命名的shell变量分配属性值,以便可以在创建输出文件时使用它们,如下所示:-

[for each <package> element processed]
..
name:<from name attribute>
path:<from nativelibrarypath attribute>
apk:<from codepath attribute>
...

XML来源是:

<package codepath="/data/app/com.project.t2i-2.apk" flags="0" ft="13a837c2068" it="13a83704ea3" name="com.project.t2i" nativelibrarypath="/data/data/com.project.t2i/lib" userid="10040" ut="13a837c2ecb" version="1">
<sigs count="1">
<cert index="3" key="308201e53082014ea0030201020204506825ae300d06092a86
4886f70d01010505003037310b30090603550406130255533110300e060355040a13074
16e64726f6964311630140603550403130d416e64726f6964204465627567301e170d31
32303933303130353735305a170d3432303932333130353735305a3037310b300906035
50406130255533110300e060355040a1307416e64726f6964311630140603550403130d
416e64726f696420446562756730819f300d06092a864886f70d010101050003818d003
08189028181009ce1c5fd64db794fd787887e8a2dccf6798ddd2fd6e1d8ab04cd8cdd9e
bf721fb3ed6be1d67c55ce729b1e1d32b200cbcfc91c798ef056bc9b2cbc66a396aed6b
a3629a18e4839353314252811412202500f11a11c3bf4eb41b2a8747c3c791c89391443
39036345b15b5e080469ac5f536fd9edffcd52dcbdf88cf43c580abd0203010001300d0
6092a864886f70d01010505000381810071fa013b4560f16640ed261262f32085a51fca
63fa6c5c46fde9a862b56b6d6f17dd49643086a39a06314426ba9a38b784601197246f8
d568e349a93bc6af315455de7a8923f40d4051a51e1658ee34aca41494ab94ce978ae38
609803dfb3004806634e6e78dd0be26fe75843958711935ffc85f9fcf81523ce23c86bc
c5c7a">
</cert></sigs>
<perms>
<item name="android.permission.WRITE_EXTERNAL_STORAGE">
</item></perms>
</package>

赞赏纯粹主义者对此不屑一顾,但是如果工具集有限,恐怕bash / awk是唯一可行的方法。接受格式不正确的XML可能不会被解析。但就目前而言,所有元素都始终以与上述相同的顺序包含属性集。

我尝试过这个,但是它简直是可怜的...

awk -F '"' '/<package.*?((codepath=)|(name=))+/{print $2}' packages.xml

1 个答案:

答案 0 :(得分:0)

在没有向我们显示预期输出的情况下,并且没有包含多个软件包的输入,我们只能猜测这是否是您想要的,但是无论如何-使用任何POSIX awk:

$ cat tst.awk
BEGIN {
    OFS=":"
    map["nativelibrarypath"] = "path"
    map["codepath"] = "apk"
    tags[++numTags] = "name"
    tags[++numTags] = "path"
    tags[++numTags] = "apk"
}
$1 == "<package"   { inPkg=1 }
$1 == "</package>" { prtPkg(); inPkg=0 }
inPkg {
    for (i=1; i<=NF; i++) {
        if ( match($i,/^[[:alnum:]_]+=/) ) {
            tag = substr($i,RSTART,RLENGTH-1)
            tag = (tag in map ? map[tag] : tag)
            val = substr($i,RSTART+RLENGTH)
            gsub(/^"|">?$/,"",val)
            tag2val[tag] = val
        }
    }
}
END { prtPkg() }

function prtPkg(        tag, tagNr) {
    if ("name" in tag2val) {
        for (tagNr=1; tagNr<=numTags; tagNr++) {
            tag = tags[tagNr]
            print tag, tag2val[tag]
        }
    }
    delete tag2val
}

$ awk -f tst.awk file
name:android.permission.WRITE_EXTERNAL_STORAGE
path:/data/data/com.project.t2i/lib
apk:/data/app/com.project.t2i-2.apk

请注意,您的输入具有2个name属性,您没有说要输出哪个属性。另外,您的key是多行的,有多种处理方式,但是由于您不希望该输出,因此我在填充tag2val数组时只保存了第一行的第一部分。