行を列に変換

行を列に変換

ハイパーバイザーで実行されている仮想マシンの詳細を含むファイルがあります。いくつかのコマンドを実行し、出力をファイルにリダイレクトします。データは次の形式にすることができます。

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を超えるVMを実行している一部のハイパーバイザーでは、この出力はハイパーバイザーによって異なります。上記のファイルは3つのVMのみを実行するハイパーバイザーの例にすぎないため、リダイレクトされたファイルには複数の(N台のVM)に関する情報が含まれると予想されます。

awk/sed またはシェルスクリプトを使用して、次の形式でこの詳細をインポートする必要があります。

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
$ 

rsOS X(およびその他のBSDシステム)でデフォルトで有効になっています。次のコマンドを使用してUbuntu(およびdebianシリーズ)にインストールできます。

sudo apt-get install rs

答え2

編集する:単純な1行ループforから必要な数の出力ラインに拡張可能:

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

元の答え:

プロセス置換を使用して、1行のコードで実行できますbash

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

この-sオプションをpaste使用すると、各ファイルを一度に処理します。:セット区切り文字は、pasteフィールドをソートして書式を美しくする最後のオプションによって「キャプチャ」されます。-scolumn

2つのプロセス置換のコマンドは、cutそれぞれ最初のフィールドと2番目のフィールドを取得します。

入力に空白行があっても構いません。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

ファイルを2回移動することが(大きな)問題ではない場合(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 2回が最良の答えだと思います。パスは、フィールドが存在する限りヘッダーフィールドのタイトルを出力します。次の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')"ksh、bash、またはzshに置き換えることができます。$'\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

関連情報