我必须遵循示例输出:
<HARDWARE>
<NAME>WIN1</NAME>
<OS>Windows 7</OS>
<IP>1.2.3.4</IP>
<DOMAIN>contoso.com</DOMAIN>
</HARDWARE>
<HARDWARE>
<NAME>WIN2</NAME>
<OS>Windows 8</OS>
<IP>10.20.30.40</IP>
<DOMAIN>contoso.com</DOMAIN>
</HARDWARE>
解析它的最佳方法是什么,它看起来像:
WIN1 Windows 7 1.2.3.4 contoso.com
WIN2 Windows 8 10.20.30.40 contoso.com
寻找使用 awk、sed 等标准工具的解决方案
答案1
对 XML 稍作修改,将所有 XML 包装在父<DATA>
标记1或您选择的另一个名为 的文件中data.xml
:
<DATA>
<HARDWARE>
<NAME>WIN1</NAME>
<OS>Windows 7</OS>
<IP>1.2.3.4</IP>
<DOMAIN>contoso.com</DOMAIN>
</HARDWARE>
<HARDWARE>
<NAME>WIN2</NAME>
<OS>Windows 8</OS>
<IP>10.20.30.40</IP>
<DOMAIN>contoso.com</DOMAIN>
</HARDWARE>
</DATA>
使用xmlstarlet
+column
xmlstarlet sel -T -t -m /DATA/HARDWARE -v "concat(NAME,' ',OS,' ',IP,' ',DOMAIN)" -n data.xml | column -t
给出:
WIN1 Windows 7 1.2.3.4 contoso.com
WIN2 Windows 8 10.20.30.40 contoso.com
编辑:
基于 Peter.O 在评论中的出色表现和他的回答如下,让我们将管道分隔的2 个输出发送到column -ts$'|'
,如下所示:
xmlstarlet sel --indent-tab -T -t -m /DATA/HARDWARE -v "concat(NAME,'|',OS,'|',IP,'|',DOMAIN)" -n data.xml | column -ts$'|'
现在,即使字段有空格,也可以很好地排列:
WIN1 Windows 7 1.2.3.4 release 5 contoso.com
Really long OS X Windows 8 10.20.30.40 contoso.com
1. 或者{ echo '<DATA>'; cat file_name; echo '</DATA>'; } | xmlstarlet ...
按照 Peter.O 在下面的评论中指出的那样使用
2. 使用空格作为分隔符无法正确对齐列
答案2
使用您的示例和 GNU sed:
sed -n 's/<[^>]*>//g;s/^ *//g;/./p' file | paste -d ";" - - - - | column -t -s ";"
输出:
WIN1 Windows 7 1.2.3.4 contoso.com WIN2 Windows 8 10.20.30.40 contoso.com
我假设您的文件不包含;
.如果您需要 CSV,请删除| column -t -s ";"
.
答案3
以下awk
脚本(加上column
输出列表)将处理放置的任何顺序子-标签,以及标签的任何空格分隔 - 即。它将处理 OP 的示例输入格式,以及以下示例没有空格和不同顺序子标签:
<HARDWARE><OS>Windows 7</OS><IP>1.2.3.4</IP><DOMAIN>contoso.com</DOMAIN><NAME>WIN1</NAME></HARDWARE><HARDWARE><NAME>WIN2</NAME><OS>Windows 8</OS><DOMAIN>contoso.com</DOMAIN><IP>10.20.30.40</IP></HARDWARE>
awk 'BEGIN{ RS="[[:space:]]*</?HARDWARE>[[:space:]]*"
FS="[[:space:]]*<|</[^<>/]+>[[:space:]]*"
tn=split( "NAME OS IP DOMAIN", tag_order, " " )
}
$0 { delete tag
for( i=1;i<=NF;i++ ) if($i) { n=index($i,">"); tag[substr($i,1,n-1)]=substr($i,n+1) }
for( i=1;i<=tn;i++ ) printf "%s\t", tag[tag_order[i]]; print ""
}' file | column -ts$'\t'
输出:
WIN1 Windows 7 1.2.3.4 contoso.com
WIN2 Windows 8 10.20.30.40 contoso.com
答案4
with awk
- 任意设置每列长度为 15 个字符,左对齐并用空格填充:
awk ' BEGIN { FS = "<[A-Za-z/]+>" } { if ( NR % 6 == 0 ) { printf"\n" } else if ( $2 != "" ) { printf"%-15s", $2 } }' file
或者像其他答案中那样结合column
awk ' BEGIN { FS = "<[A-Za-z/]+>" } { if ( NR % 6 == 0 ) { printf"\n" } else if ( $2 != "" ) { printf"%s ", $2 } }' file | column -t