将行转换为列


10

我有一个文件,其中包含有关在管理程序中运行的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

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

我们需要使用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

Answers:


1

如果两次浏览文件不是一个大问题(在内存中仅存储一行):

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')"是用漂亮的方式格式化整个表格。
请注意,"$(printf '%b' '\t')"可以用$'\t'ksh,bash或zsh 替换。


8

如果您拥有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

6

编辑:在一个简单的单线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-s选项“捕获”,column通过使字段对齐来修饰格式。

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

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

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

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

2
这适用于两个输出行,但对于更多行,则变为无效。

2

使用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


将答案更改为动态。只需要每个文件只有1个VM数据即可。
jecxjo

1
declare -a COLS
declare -a DATA
while IFS=':' read -ra fields; do
   COLS+=("${fields[0]}")
   DATA+=("${fields[1]}")
done < <( cat /path/to/input.txt)

HEADER=""
DATA=""
for i in $(seq 0 $((${#fields[@]}-1)); do
    HEADER="${HEADER}${COLS[$i]} "
    DATA="${DATA}${COLS[$i]} "
done
echo $HEADER
echo $DATA

1

随着gnu datamashcolumn来自util-linux

datamash -t: transpose <infile | column -t -s:

这适用于两列以上,但假定您的输入文件中没有空行。中间有空行(如您的初始输入示例中的行),您将收到以下错误:

datamash: transpose input error: line 2 has 0 fields (previous lines had 2);

因此,为了避免在处理之前必须挤压它们datamash

tr -s \\n <infile | datamash -t: transpose | column -t -s:

否则,在这种特殊情况下(仅两列),带有zsh和相同column

list=(${(f)"$(<infile)"})
printf %s\\n ${(j;:;)list[@]%:*} ${(j;:;)list[@]#*:} | column -t -s:

(${(f)"$(<infile)"})读取数组中的行;${(j;:;)list[@]%:*}联接(与:)每个元素的第一个字段,并${(j;:;)list[@]#*:}联接(与:)每个元素的第二个字段;这些都被打印,例如输出是

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

然后通过管道传输到 column -t -s:


0

cat <(head -n 11 virtual.txt | cut -d: -f1) <(sed 's/.*: //' virtual.txt) | xargs -d '\n' -n 11 | column -t

在这种情况下,每个虚拟机的行数是硬编码的-11。最好事先将其计数并存储到变量中,然后在代码中使用此变量。

说明

  1. cat <(command 1) <(command 2)- <()构造使command输出看起来像一个临时文件。因此,cat连接两个文件并进一步传送它。

    • 命令1head -n 11 virtual.txt | cut -d: -f1,给我们未来的列标题。一个虚拟机条目是前十一行,该head命令用于获取它。该cut拆分此项以两列打印仅第一个。
    • 命令2sed 's/.*: //' virtual.txt-给我们将来的列值。sed删除所有不需要的文本,仅保留值。
  2. xargs -d '\n' -n 11。每个输入项均以换行符终止。此命令获取项目并按每行11条打印它们。

  3. column -t-漂亮打印显示器时需要。它以表格形式显示我们的行。否则,每行的宽度将不同。

输出量

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

0

使用datamash及其transpose选项交换文件中的行和列。

datamash -t: transpose < infile.txt

默认情况下,转置会验证输入在每行中具有相同数量的字段,否则将失败并显示错误,您可以禁用其严格模式以允许缺少值 --no-strict

datamash -t: --no-strict transpose < infile.txt

您还可以使用它--filler来设置缺失字段填充值:

datamash -t: --no-strict --filler " " transpose < infile.txt

衍生自 datamash manual


-5

如果您的数据在目录中的单独文件中,则可以使用:

for file in $(ls $DIRECTORY)
do
  cat ${file} | while read line
  do
    value=$(echo $line | cut -d: -f2-)
    printf "%s\t" "${value}" >> bigfile
  done
  echo " " >> bigfile
done

如果变量值的长度不同,则可能需要在行\t上按摩(制表符)字符的数量printf

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.