将行转换为列

将行转换为列

我有一个文件,其中包含有关在虚拟机管理程序中运行的虚拟机的详细信息。我们运行一些命令并将输出重定向到文件。数据可采用以下格式。

Virtual Machine : OL6U5
        ID     : 0004fb00000600003da8ce6948c441bb
        Status : Running
        Memory : 65536
        Uptime : 17835 Minutes
        Server : MyOVS1.vmorld.com
        Pool   : HA-POOL
        HA Mode: false
        VCPU   : 16
        Type   : Xen PVM
        OS     : Oracle Linux 6
Virtual Machine : OL6U6
        ID     : 0004fb00000600003da8ce6948c441bc
        Status : Running
        Memory : 65536
        Uptime : 17565 Minutes
        Server : MyOVS2.vmorld.com
        Pool   : NON-HA-POOL
        HA Mode: false
        VCPU   : 16
        Type   : Xen PVM
        OS     : Oracle Linux 6
Virtual Machine : OL6U7
        ID     : 0004fb00000600003da8ce6948c441bd
        Status : Running
        Memory : 65536
        Uptime : 17835 Minutes
        Server : MyOVS1.vmorld.com
        Pool   : HA-POOL
        HA Mode: false
        VCPU   : 16
        Type   : Xen PVM
        OS     : Oracle Linux 6

此输出因虚拟机管理程序而异,因为在某些虚拟机管理程序上我们运行着 50 多个虚拟机。上面的文件只是虚拟机管理程序的一个示例,其中我们只运行 3 个虚拟机,因此重定向的文件预计包含有关多个(N 个虚拟机)的信息

我们需要使用 awk/sed 或 shell 脚本以以下格式获取此详细信息

Virtual_Machine  ID                                Status   Memory  Uptime  Server              Pool        HA     VCPU  Type     OS
OL6U5            0004fb00000600003da8ce6948c441bb  Running  65536   17835   MyOVS1.vmworld.com  HA-POOL     false  16    Xen PVM  Oracle Linux 6
OL6U6            0004fb00000600003da8ce6948c441bc  Running  65536   17565   MyOVS2.vmworld.com  NON-HA-POOL     false  16    Xen PVM  Oracle Linux 6
OL6U5            0004fb00000600003da8ce6948c441bd  Running  65536   17835   MyOVS1.vmworld.com  HA-POOL     false  16    Xen PVM  Oracle Linux 6

答案1

如果您有rs(重塑)效用可用时,您可以执行以下操作:

rs -Tzc: < input.txt

这给出了与问题中指定的输出格式完全相同的格式,甚至精确到动态列宽度。

  • -T转置输入数据
  • -z根据每列的最大值适当调整列的大小
  • -c:使用冒号作为输入字段分隔符

这适用于任意大小的表,例如:

$ echo "Name:Alice:Bob:Carol
Age:12:34:56
Eyecolour:Brown:Black:Blue" | rs -Tzc: 
Name   Age  Eyecolour
Alice  12   Brown
Bob    34   Black
Carol  56   Blue
$ 

rs默认情况下在 OS X(以及可能的其他 BSD 机器)上可用。它可以通过以下命令安装在 Ubuntu(和 debian 系列)上:

sudo apt-get install rs

答案2

编辑:在一个简单的单行for循环中可扩展到任意数量的输出行:

for ((i=1;i<=2;i++)); do cut -d: -f "$i" input | paste -sd: ; done | column -t -s:

原答案:

您可以使用流程替换将其作为单行代码执行bash

paste -sd: <(cut -d: -f1 input) <(cut -d: -f2 input) | column -t -s:

-s选项paste使其一次处理每个文件。:设置的分隔符被最后的选项paste“捕获” ,通过使字段对齐来美化格式。-scolumn

两个进程替换中的命令cut分别拉出第一个字段和第二个字段。

输入中是否有空行并不重要,因为column -t -s:无论如何都会清理输出。 (问题中指定的原始输入中有空行,但它们已被删除。无论空行如何,上述命令都有效。)

输入 - 上述命令中名为“input”的文件的内容:

Virtual_Machine:OL6U7

ID:0004fb00000600003da8ce6948c441bd

Status:Running

Memory:65536

Uptime:17103

Server:MyOVS1.vmworld.com

Pool:HA-POOL

HA:false

VCPU:16

Type:Xen PVM

OS:Oracle Linux 6

输出:

Virtual_Machine  ID                                Status   Memory  Uptime  Server              Pool     HA     VCPU  Type     OS
OL6U7            0004fb00000600003da8ce6948c441bd  Running  65536   17103   MyOVS1.vmworld.com  HA-POOL  false  16    Xen PVM  Oracle Linux 6

答案3

如果两次遍历文件不是一个(大)问题(只会在内存中存储一​​行):

awk -F : '{printf("%s\t ", $1)}' infile
echo
awk -F : '{printf("%s\t ", $2)}' infile

对于字段的一般计数,其中可能有许多文件路径:

#!/bin/bash
rowcount=2
for (( i=1; i<=rowcount; i++ )); do
    awk -v i="$i" -F : '{printf("%s\t ", $i)}' infile
    echo
done

但对于真正通用的转置,这将起作用:

awk '$0!~/^$/{    i++;
                  split($0,arr,":");
                  for (j in arr) {
                      out[i,j]=arr[j];
                      if (maxr<j){ maxr=j} # max number of output rows.
                  }
            }
    END {
        maxc=i                             # max number of output columns.
        for     (j=1; j<=maxr; j++) {
            for (i=1; i<=maxc; i++) {
                printf( "%s\t", out[i,j])  # out field separator.
            }
            printf( "%s\n","" )
        }
    }' infile

并使其美观(使用制表符\t作为字段分隔符):

./script | |column -t -s $'\t'

Virtual_Machine  ID                                Status   Memory  Uptime  Server              Pool     HA     VCPU  Type     OS
OL6U7            0004fb00000600003da8ce6948c441bd  Running  65536   17103   MyOVS1.vmworld.com  HA-POOL  false  16    Xen PVM  Oracle Linux 6

上面的通用转置代码会将整个矩阵存储在内存中。
对于非常大的文件来说这可能是一个问题。


更新新文本。

为了处理问题中发布的新文本,在我看来,两遍 awk 是最好的答案。只要字段存在,一次传递将打印标题字段标题。下一个 awk 遍将仅打印字段 2。在这两种情况下,我都添加了一种删除前导空格和尾随空格的方法(为了更好的格式)。

#!/bin/bash
{
awk -F: 'BEGIN{ sl="Virtual Machine"}
         $1~sl && head == 1 { head=0; exit 0}
         $1~sl && head == 0 { head=1; }
         head == 1 {
             gsub(/^[ \t]+/,"",$1);   # remove leading  spaces
             gsub(/[ \t]+$/,"",$1);   # remove trailing spaces
             printf( "%s\t", $1)
         }
         ' infile
#echo
awk -F: 'BEGIN { sl="Virtual Machine"}
         $1~sl { printf( "%s\n", "") }
         {
             gsub(/^[ \t]+/,"",$2);   # remove leading  spaces
             gsub(/[ \t]+$/,"",$2);   # remove trailing spaces
             printf( "%s\t", $2)
         }
         ' infile
echo
} | column -t -s "$(printf '%b' '\t')"

周围的{ ... } | column -t -s "$(printf '%b' '\t')"是以漂亮的方式格式化整个表格。
请注意,可以用ksh、bash 或 zsh"$(printf '%b' '\t')"替换。$'\t'

答案4

使用 awk 存储键和值并最后打印出来。

#!/usr/bin/awk -f
BEGIN {
  CNT=0
  FS=":"
}

{
  HDR[CNT]=$1;
  ENTRY[CNT]=$2;
  CNT++;
}

END {
  for (x = 0; x < CNT; x++)
    printf "%s\t",HDR[x]

  print""

  for (x = 0; x < CNT; x++)
    printf "%s\t",ENTRY[x]
  }

刚刚跑的awk -f ./script.awk ./input.txt

相关内容