使用xmlstarlet按特定顺序解析列表
我正在尝试使用xmlstarlet sel列出需要从xml文件创建的磁盘分区,该文件在磁盘上以升序块位置列出这些分区(示例:) 此文件是通过转储必须复制的已安装系统生成的。然后,用户可以用“*”替换他想要适应新磁盘的分区大小 现在我正在做以下工作:使用xmlstarlet按特定顺序解析列表,xml,bash,sorting,xslt,xmlstarlet,Xml,Bash,Sorting,Xslt,Xmlstarlet,我正在尝试使用xmlstarlet sel列出需要从xml文件创建的磁盘分区,该文件在磁盘上以升序块位置列出这些分区(示例:) 此文件是通过转储必须复制的已安装系统生成的。然后,用户可以用“*”替换他想要适应新磁盘的分区大小 现在我正在做以下工作: local IFS=; DISK_DEV=sda DISKS_LAYOUT_FILE=/tmp/disk-layout-complex.xml cd /tmp wget https://raw.githubus
local IFS=;
DISK_DEV=sda
DISKS_LAYOUT_FILE=/tmp/disk-layout-complex.xml
cd /tmp
wget https://raw.githubusercontent.com/finley/SystemImager/initrd-from-imageserver-and-dont-package-initrd/doc/examples/disk-layout-complex.xml
xmlstarlet sel -t -m "config/disk[@dev=\"${DISK_DEV}\"]/part" -v "concat(@num,';',@size,';',@p_type,';',@id,';',@p_name,';',@flags,';',@lvm_group,';',@raid_dev)" -n ${DISKS_LAYOUT_FILE} | sed '/^\s*$/d' |\
while read P_NUM P_SIZE P_TYPE P_ID P_NAME P_FLAGS P_LVM_GROUP P_RAID_DEV
do
# process partitions creation.
echo "Creating partition $P_NUM of size $P_SIZE tpye $P_TYPE"
done
上述xmlstarlet将生成以下输出,然后由while read循环处理:
1;500;primary;;;boot;;
3;4096;primary;;;;;;
4;*;extended;;;;;;
7;4096;logical;;;;;;
5;*;logical;;;;;;
6;2048;logical;;;;;;
2;1024;primary;;;swap;;
在处理第3行(分区#4)后,磁盘上没有剩余空间,循环将处理第4行(分区#7),并在磁盘上没有剩余空间的情况下失败
问题在于可变大小分区(在文件中使用100%(“*”)。如果一个列在其他剩余的列之前(在上面的例子中是第4部分),那么创建它时会有完整的剩余空间,磁盘上没有空间来处理最后一个。因此,例如,不可能将主交换分区放在具有可变大小的/分区的磁盘的末尾
问:有没有一种聪明的方法可以使用xmlstarlet sel按以下顺序列出分区:
按照写入xml文件的相同顺序列出所有主分区和扩展分区,直到看到大小为“*”的分区
- 记住这个可变大小的分区
- 然后从末尾按相反顺序列出其他分区
- 最后打印可变大小的分区
- 对逻辑分区重复操作(如果有)
我非常确信有一种解决方案可以完成大部分工作(如果不是全部的话),但我的技能远远不够,甚至无法评估它是否可以通过这种方式完成。我认为我可以在纯bash中实现这一点,但这将远远不够优雅。在广泛搜索和学习了xslt的基础知识之后,似乎这正是我想要的 (此处提供要处理的xml文件的完整源:) 递归算法如下所示:
do_partition_template(index, type)
if partition(index) is same type and if variable_partition is not yet seen:
print "normal;line"
do_partition_template(index+1,type)
if partition(index) is same type and if variable partition has been seen:
do_partition_template(index+1, type)
print "reverse;line"
if(partition(index) is same type and if size(partition)="*":
do_partition_template(index+1, type)
print "normal;line"
if partition is not the same type:
do_partition_template(index+1, type)
fi
call template 1st partition type='primary|extended'
call template 1st partition type='logical'
我不确定算法的递归形式,但需要按顺序创建的是:
-从磁盘开始创建的主/扩展分区列表
-要从磁盘末尾创建的主/扩展分区列表
-具有size=“”的主/扩展分区
-从扩展分区开始创建的逻辑分区列表
-要从扩展分区末尾创建的逻辑分区列表
-大小为“”的逻辑分区
作为xsl的新手,解决这个问题对我来说非常复杂。
我使用了xmlstarlet sel-C-t-m“config/disk[@dev=\'”/dev/sda\“]/part“-v”concat(@num,“;”,@size,“;”,@p_type,“;”,@id,“;”,@p_name,“;”,@flags,“;”,@lvm_group,“,@raid_dev)”-n./disk-layout-complex.xml>do_part.xslt
首先是我的问题,但是对于我来说很难形式化一个模板,它将在两次扫描中命中所有分区(一次用于主/扩展分区,另一次用于逻辑分区)
在没有变量的情况下工作并不容易。在广泛搜索和学习了xslt的基础知识之后,我似乎正在寻找它 (此处提供要处理的xml文件的完整源:) 递归算法如下所示:
do_partition_template(index, type)
if partition(index) is same type and if variable_partition is not yet seen:
print "normal;line"
do_partition_template(index+1,type)
if partition(index) is same type and if variable partition has been seen:
do_partition_template(index+1, type)
print "reverse;line"
if(partition(index) is same type and if size(partition)="*":
do_partition_template(index+1, type)
print "normal;line"
if partition is not the same type:
do_partition_template(index+1, type)
fi
call template 1st partition type='primary|extended'
call template 1st partition type='logical'
我不确定算法的递归形式,但需要按顺序创建的是:
-从磁盘开始创建的主/扩展分区列表
-要从磁盘末尾创建的主/扩展分区列表
-具有size=“”的主/扩展分区
-从扩展分区开始创建的逻辑分区列表
-要从扩展分区末尾创建的逻辑分区列表
-大小为“”的逻辑分区
作为xsl的新手,解决这个问题对我来说非常复杂。
我使用了xmlstarlet sel-C-t-m“config/disk[@dev=\'”/dev/sda\“]/part“-v”concat(@num,“;”,@size,“;”,@p_type,“;”,@id,“;”,@p_name,“;”,@flags,“;”,@lvm_group,“,@raid_dev)”-n./disk-layout-complex.xml>do_part.xslt
首先是我的问题,但是对于我来说很难形式化一个模板,它将在两次扫描中命中所有分区(一次用于主/扩展分区,另一次用于逻辑分区)
在没有变量的情况下工作并不容易。最终答案如下
<!— Sample cut, relevant for this question —>
<config>
<disk dev="/dev/sda" label_type="msdos" unit_of_measurement="MiB">
<part num="1" size="500" p_type="primary" flags="boot" />
<part num="3" size="4096" p_type="primary" />
<part num="4" size="*" p_type="extended" />
<part num="7" size="4096" p_type="logical" />
<part num="5" size="*" p_type="logical" />
<part num="6" size="2048" p_type="logical" />
<part num="2" size="1024" p_type="primary" flags="swap" />
</disk>
</config>
可通过以下方式运行sxl转换文件获得:
xmlstarlet tr do_part.xsl ./disk-layout-complex.xml
现在是代码:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Call me with:
xmlstarlet tr do_part.xsl disk-layout.xml
Output: List of partitions to create in order.
Each line list the following values separated by semicolons:
- disk device
- creation reference
- partition number
- partition size
- partition size unit
- partition type
- partition id
- partition name
- partition flags
- lvm group it belongs to
- raid device it belongs to
Author: Olivier LAHAYE (c) 2019
Licence: GPLv2
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
<xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/config/disk"> <!-- We are loking for disk informations only -->
<!-- For each disk block -->
<xsl:call-template name="PrintPartition"> <!-- Compute primary or extended partitions to create -->
<xsl:with-param name="index"><xsl:value-of select="count(part)"/></xsl:with-param>
<xsl:with-param name="reference">end</xsl:with-param>
<xsl:with-param name="type">primary|extended</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="PrintPartition"> <!-- then, compute logical partitions to create -->
<xsl:with-param name="index"><xsl:value-of select="count(part)"/></xsl:with-param>
<xsl:with-param name="reference">end</xsl:with-param>
<xsl:with-param name="type">logical</xsl:with-param>
</xsl:call-template>
</xsl:template> <!-- We're done -->
<!-- Main recursive template that will dump partitions to create for the matched disk -->
<xsl:template name="PrintPartition">
<xsl:param name="index"/> <!-- partition node number within disk item-->
<xsl:param name="reference"/> <!-- beginning or end: should we create partition relative from beginning or from end of free space -->
<xsl:param name="type"/> <!-- type of partitions -->
<xsl:choose>
<xsl:when test="$index=1">
<xsl:if test="contains($type,part[position()=$index]/@p_type)">
<xsl:value-of select="concat(@dev,';',$reference,';',part[position()=$index]/@num,';',part[position()=$index]/@size,';',@unit_of_measurement,';',part[position()=$index]/@p_type,';',part[position()=$index]/@id,';',part[position()=$index]/@p_name,';',part[position()=$index]/@flags,';',part[position()=$index]/@lvm_group,';',part[position()=$index]/@raid_dev,' ')"/> <!-- write partition information -->
</xsl:if>
</xsl:when>
<xsl:when test="contains($type,part[position()=$index]/@p_type) and part[position()=$index]/@size!='*'">
<xsl:if test="$reference='end'">
<xsl:value-of select="concat(@dev,';',$reference,';',part[position()=$index]/@num,';',part[position()=$index]/@size,';',@unit_of_measurement,';',part[position()=$index]/@p_type,';',part[position()=$index]/@id,';',part[position()=$index]/@p_name,';',part[position()=$index]/@flags,';',part[position()=$index]/@lvm_group,';',part[position()=$index]/@raid_dev,' ')"/> <!-- write partition information -->
</xsl:if>
<xsl:call-template name="PrintPartition">
<xsl:with-param name="index"><xsl:value-of select="number($index)-1"/></xsl:with-param>
<xsl:with-param name="reference"><xsl:value-of select="$reference"/></xsl:with-param>
<xsl:with-param name="type"><xsl:value-of select="$type"/></xsl:with-param>
</xsl:call-template>
<xsl:if test="$reference='beginning'">
<xsl:value-of select="concat(@dev,';',$reference,';',part[position()=$index]/@num,';',part[position()=$index]/@size,';',@unit_of_measurement,';',part[position()=$index]/@p_type,';',part[position()=$index]/@id,';',part[position()=$index]/@p_name,';',part[position()=$index]/@flags,';',part[position()=$index]/@lvm_group,';',part[position()=$index]/@raid_dev,' ')"/> <!-- write partition information -->
</xsl:if>
</xsl:when>
<xsl:when test="contains($type,part[position()=$index]/@p_type) and part[position()=$index]/@size='*'">
<xsl:call-template name="PrintPartition">
<xsl:with-param name="index"><xsl:value-of select="number($index)-1"/></xsl:with-param>
<xsl:with-param name="reference">beginning</xsl:with-param>
<xsl:with-param name="type"><xsl:value-of select="$type"/></xsl:with-param>
</xsl:call-template>
<xsl:value-of select="concat(@dev,';','beginning;',part[position()=$index]/@num,';',part[position()=$index]/@size,';',@unit_of_measurement,';',part[position()=$index]/@p_type,';',part[position()=$index]/@id,';',part[position()=$index]/@p_name,';',part[position()=$index]/@flags,';',part[position()=$index]/@lvm_group,';',part[position()=$index]/@raid_dev,' ')"/> <!-- write partition information -->
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="PrintPartition">
<xsl:with-param name="index"><xsl:value-of select="number($index)-1"/></xsl:with-param>
<xsl:with-param name="reference"><xsl:value-of select="$reference"/></xsl:with-param>
<xsl:with-param name="type"><xsl:value-of select="$type"/></xsl:with-param>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
结束
初级|扩展
结束
符合逻辑的
开始
瞧,它工作得很好
当然有更好或更优雅的解决方案。(fe)
/dev/sda;end;2;1024;MiB;primary;;;swap;;
/dev/sda;beginning;1;500;MiB;primary;;;boot;;
/dev/sda;beginning;3;4096;MiB;primary;;;;;
/dev/sda;beginning;4;*;MiB;extended;;;;;
/dev/sda;end;6;2048;MiB;logical;;;;;
/dev/sda;beginning;7;4096;MiB;logical;;;;;
/dev/sda;beginning;5;*;MiB;logical;;;;;
xmlstarlet tr do_part.xsl ./disk-layout-complex.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- Call me with:
xmlstarlet tr do_part.xsl disk-layout.xml
Output: List of partitions to create in order.
Each line list the following values separated by semicolons:
- disk device
- creation reference
- partition number
- partition size
- partition size unit
- partition type
- partition id
- partition name
- partition flags
- lvm group it belongs to
- raid device it belongs to
Author: Olivier LAHAYE (c) 2019
Licence: GPLv2
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
<xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/config/disk"> <!-- We are loking for disk informations only -->
<!-- For each disk block -->
<xsl:call-template name="PrintPartition"> <!-- Compute primary or extended partitions to create -->
<xsl:with-param name="index"><xsl:value-of select="count(part)"/></xsl:with-param>
<xsl:with-param name="reference">end</xsl:with-param>
<xsl:with-param name="type">primary|extended</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="PrintPartition"> <!-- then, compute logical partitions to create -->
<xsl:with-param name="index"><xsl:value-of select="count(part)"/></xsl:with-param>
<xsl:with-param name="reference">end</xsl:with-param>
<xsl:with-param name="type">logical</xsl:with-param>
</xsl:call-template>
</xsl:template> <!-- We're done -->
<!-- Main recursive template that will dump partitions to create for the matched disk -->
<xsl:template name="PrintPartition">
<xsl:param name="index"/> <!-- partition node number within disk item-->
<xsl:param name="reference"/> <!-- beginning or end: should we create partition relative from beginning or from end of free space -->
<xsl:param name="type"/> <!-- type of partitions -->
<xsl:choose>
<xsl:when test="$index=1">
<xsl:if test="contains($type,part[position()=$index]/@p_type)">
<xsl:value-of select="concat(@dev,';',$reference,';',part[position()=$index]/@num,';',part[position()=$index]/@size,';',@unit_of_measurement,';',part[position()=$index]/@p_type,';',part[position()=$index]/@id,';',part[position()=$index]/@p_name,';',part[position()=$index]/@flags,';',part[position()=$index]/@lvm_group,';',part[position()=$index]/@raid_dev,' ')"/> <!-- write partition information -->
</xsl:if>
</xsl:when>
<xsl:when test="contains($type,part[position()=$index]/@p_type) and part[position()=$index]/@size!='*'">
<xsl:if test="$reference='end'">
<xsl:value-of select="concat(@dev,';',$reference,';',part[position()=$index]/@num,';',part[position()=$index]/@size,';',@unit_of_measurement,';',part[position()=$index]/@p_type,';',part[position()=$index]/@id,';',part[position()=$index]/@p_name,';',part[position()=$index]/@flags,';',part[position()=$index]/@lvm_group,';',part[position()=$index]/@raid_dev,' ')"/> <!-- write partition information -->
</xsl:if>
<xsl:call-template name="PrintPartition">
<xsl:with-param name="index"><xsl:value-of select="number($index)-1"/></xsl:with-param>
<xsl:with-param name="reference"><xsl:value-of select="$reference"/></xsl:with-param>
<xsl:with-param name="type"><xsl:value-of select="$type"/></xsl:with-param>
</xsl:call-template>
<xsl:if test="$reference='beginning'">
<xsl:value-of select="concat(@dev,';',$reference,';',part[position()=$index]/@num,';',part[position()=$index]/@size,';',@unit_of_measurement,';',part[position()=$index]/@p_type,';',part[position()=$index]/@id,';',part[position()=$index]/@p_name,';',part[position()=$index]/@flags,';',part[position()=$index]/@lvm_group,';',part[position()=$index]/@raid_dev,' ')"/> <!-- write partition information -->
</xsl:if>
</xsl:when>
<xsl:when test="contains($type,part[position()=$index]/@p_type) and part[position()=$index]/@size='*'">
<xsl:call-template name="PrintPartition">
<xsl:with-param name="index"><xsl:value-of select="number($index)-1"/></xsl:with-param>
<xsl:with-param name="reference">beginning</xsl:with-param>
<xsl:with-param name="type"><xsl:value-of select="$type"/></xsl:with-param>
</xsl:call-template>
<xsl:value-of select="concat(@dev,';','beginning;',part[position()=$index]/@num,';',part[position()=$index]/@size,';',@unit_of_measurement,';',part[position()=$index]/@p_type,';',part[position()=$index]/@id,';',part[position()=$index]/@p_name,';',part[position()=$index]/@flags,';',part[position()=$index]/@lvm_group,';',part[position()=$index]/@raid_dev,' ')"/> <!-- write partition information -->
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="PrintPartition">
<xsl:with-param name="index"><xsl:value-of select="number($index)-1"/></xsl:with-param>
<xsl:with-param name="reference"><xsl:value-of select="$reference"/></xsl:with-param>
<xsl:with-param name="type"><xsl:value-of select="$type"/></xsl:with-param>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
1;500;primary;boot
3;4096;primary;
2;1024;primary;swap
4;*;extended;
7;4096;logical;
6;2048;logical;
5;*;logical;