将行转换为列

Ign*_*eLX 12 sed awk text-processing

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

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
Run Code Online (Sandbox Code Playgroud)

此输出因管理程序而异,因为在某些管理程序上,我们有 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
Run Code Online (Sandbox Code Playgroud)

Dig*_*uma 11

如果您有rs(reshape) 实用程序可用,您可以执行以下操作:

rs -Tzc: < input.txt
Run Code Online (Sandbox Code Playgroud)

这提供了与问题中指定的完全相同的输出格式,甚至可以降低到动态列宽。

  • -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
$ 
Run Code Online (Sandbox Code Playgroud)

rs默认情况下在 OS X 上可用(可能还有其他 BSD 机器)。它可以安装在 Ubuntu(和 debian 系列)上:

sudo apt-get install rs
Run Code Online (Sandbox Code Playgroud)


Wil*_*ard 7

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

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

原答案:

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

paste -sd: <(cut -d: -f1 input) <(cut -d: -f2 input) | column -t -s:
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

输出:

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
Run Code Online (Sandbox Code Playgroud)

  • 这适用于两个输出行,但对于更多行,它变得笨拙。 (2认同)

小智 3

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

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

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

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

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

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
Run Code Online (Sandbox Code Playgroud)

并使其美观(使用制表符\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
Run Code Online (Sandbox Code Playgroud)

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


更新新文本。

为了处理问题中发布的新文本,在我看来,两遍 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')"
Run Code Online (Sandbox Code Playgroud)

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