使用 shell 脚本从 xml 标签获取属性值并转换为 csv
Get attribute value from xml tags with shell script and convert to csv
任务:
我正在尝试使用 shell 脚本从 xml 标签获取属性值,将值拆分并保存在 .csv 文件中。
这是 xml 的样子:
<host>
<servers>
<server name="Type1Name1-Port1" >...</server>
<server name="Type2Name2-Port2" >...</server>
<server name="Type3Name3-Port3" >...</server>
...
<server name="TypexNamex-Portx" >...</server>
</servers>
</host>
我想从 "name" 属性中获取值并将它们拆分如下:
Type;Name;Port
我想要的输出 csv 文件应该是这样的:
Type1;Name1;Port1
Type2;Name2;Port2
Type3;Name3;Port3
...
Typex;Namex;Portx
问题:
- 我无法在服务器上安装任何东西
- 我只能用"ksh-awk" / "xmllint wihtout --xpath" / "standard linux commands"
我可以使用任何我想使用的 shell 语言。我更喜欢 bash 和 ksh.
我的问题:
- 你觉得我的任务有可能解决吗?
- 子任务的最佳方法是什么? (读、分、写)
编辑:
服务器名称的示例数据:
T-TTT_AAA-A-SSS-PPPP
其中 T 表示类型,A 表示应用程序名称,S 表示服务器名称,P 表示端口。 T、A和S的长度是可变的。 P 是常数。
这是我想出的,只使用常用工具:xmllint
和 sed
:
echo 'cat //host/servers/server/@name' | xmllint --shell data.xml | sed -n 's: name=\"\([A-Z][a-z0-9]*\)\([A-Z][a-z0-9]*\)-\(.*\)\":,,:p'
sed
部分是根据发布时 OP 的示例完成的。
细分:
echo 'cat //host/servers/server/@name'
:我们将此命令传递给 xmllint
。它将捕获 <host><servers><server ...> ... </server></servers></hosts>
内所有节点的 name
属性
xmllint --shell data.xml
:遍历 data.xml
并执行在交互式 shell. 中作为参数传递的命令
sed -n 's: name=\"\([A-Z][a-z0-9]*\)\([A-Z][a-z0-9]*\)-\(.*\)\":;;:p'
:我们处理 xmllint
的输出以仅保留我们感兴趣的数据
xmllint
将产生以下输出:name="Type1Name1-Port1"
- 我们定义了 3 个捕获组:一个大写字母后跟除大写以外的任何字符(
Type
),另一个大写字母后跟除大写以外的任何字符(Name
),以及任何字符在 -
和 "
字符之间
- 我们告诉 sed 只打印匹配的字符串,用分号分隔
输出:
Type1;Name1;Port1
Type2;Name2;Port2
Type3;Name3;Port3
Typex;Namex;Portx
编辑:
为了适应您在评论中指出的模式,您只需更改 sed 正则表达式,例如:
sed -n 's: name=\"\(.*\)_\(.*\)-\(.\{4\}\)\":,,:p'
这将匹配格式 T-TTT_AAA-A-SSS-PPPP
,类型和服务器名称的长度不限。尝试围绕正则表达式 fiddle 或在 regex
标签中提出另一个问题,如果这不是您所需要的。
如果没有 xmllint,您可以像这样解析输入
<host>
<servers>
<server name="Type1_Name1-Port1" >...</server>
<server name="Type-2_Name2-Port2" >...</server>
<server name="Type3_Name-3-Port3" >...</server>
</servers>
</host>
和
sed -n '/<server name=/ s/[^"]*"\([^_]*\)_\([^"]*\)-\([^"]*\)".*/;;/p' inputfile
xidel -e '//server/@name' f.xml | sed ...
任务:
我正在尝试使用 shell 脚本从 xml 标签获取属性值,将值拆分并保存在 .csv 文件中。
这是 xml 的样子:
<host>
<servers>
<server name="Type1Name1-Port1" >...</server>
<server name="Type2Name2-Port2" >...</server>
<server name="Type3Name3-Port3" >...</server>
...
<server name="TypexNamex-Portx" >...</server>
</servers>
</host>
我想从 "name" 属性中获取值并将它们拆分如下:
Type;Name;Port
我想要的输出 csv 文件应该是这样的:
Type1;Name1;Port1
Type2;Name2;Port2
Type3;Name3;Port3
...
Typex;Namex;Portx
问题:
- 我无法在服务器上安装任何东西
- 我只能用"ksh-awk" / "xmllint wihtout --xpath" / "standard linux commands"
我可以使用任何我想使用的 shell 语言。我更喜欢 bash 和 ksh.
我的问题:
- 你觉得我的任务有可能解决吗?
- 子任务的最佳方法是什么? (读、分、写)
编辑:
服务器名称的示例数据:
T-TTT_AAA-A-SSS-PPPP
其中 T 表示类型,A 表示应用程序名称,S 表示服务器名称,P 表示端口。 T、A和S的长度是可变的。 P 是常数。
这是我想出的,只使用常用工具:xmllint
和 sed
:
echo 'cat //host/servers/server/@name' | xmllint --shell data.xml | sed -n 's: name=\"\([A-Z][a-z0-9]*\)\([A-Z][a-z0-9]*\)-\(.*\)\":,,:p'
sed
部分是根据发布时 OP 的示例完成的。
细分:
echo 'cat //host/servers/server/@name'
:我们将此命令传递给xmllint
。它将捕获<host><servers><server ...> ... </server></servers></hosts>
内所有节点的 xmllint --shell data.xml
:遍历data.xml
并执行在交互式 shell. 中作为参数传递的命令
sed -n 's: name=\"\([A-Z][a-z0-9]*\)\([A-Z][a-z0-9]*\)-\(.*\)\":;;:p'
:我们处理xmllint
的输出以仅保留我们感兴趣的数据xmllint
将产生以下输出:name="Type1Name1-Port1"
- 我们定义了 3 个捕获组:一个大写字母后跟除大写以外的任何字符(
Type
),另一个大写字母后跟除大写以外的任何字符(Name
),以及任何字符在-
和"
字符之间 - 我们告诉 sed 只打印匹配的字符串,用分号分隔
name
属性
输出:
Type1;Name1;Port1
Type2;Name2;Port2
Type3;Name3;Port3
Typex;Namex;Portx
编辑:
为了适应您在评论中指出的模式,您只需更改 sed 正则表达式,例如:
sed -n 's: name=\"\(.*\)_\(.*\)-\(.\{4\}\)\":,,:p'
这将匹配格式 T-TTT_AAA-A-SSS-PPPP
,类型和服务器名称的长度不限。尝试围绕正则表达式 fiddle 或在 regex
标签中提出另一个问题,如果这不是您所需要的。
如果没有 xmllint,您可以像这样解析输入
<host>
<servers>
<server name="Type1_Name1-Port1" >...</server>
<server name="Type-2_Name2-Port2" >...</server>
<server name="Type3_Name-3-Port3" >...</server>
</servers>
</host>
和
sed -n '/<server name=/ s/[^"]*"\([^_]*\)_\([^"]*\)-\([^"]*\)".*/;;/p' inputfile
xidel -e '//server/@name' f.xml | sed ...