使用 awk 行到列

使用 awk 行到列

我必须遵循示例输出:

<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

相关内容