行を列に変換する


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

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

2
可能性のある重複ファイルの列への変換行
αғsнιη

回答:


1

ファイルを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つのパスが最良の答えであるように思えます。1つのパスは、フィールドが存在する限り、ヘッダーフィールドのタイトルを印刷します。次の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'


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
$ 

rsOS 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それは時に各ファイル1を処理します。で:設定された区切り文字pasteは、フィールドを整列させることによってフォーマットをきれいにするために、-sオプションcolumnの最後に「キャッチ」されます。

cut2つのプロセス置換のコマンドは、それぞれ最初のフィールドと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

2
これは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 2016年

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 datamashしてcolumnからutil-linux

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

これは3つ以上の列で機能しますが、入力ファイルに空の行がないことを前提としています。(最初の入力サンプルのように)間に空白行があると、次のようなエラーが発生します。

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

で処理する前にそれらを絞る必要があることを避けるためにdatamash

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

それ以外の場合、この特定のケース(2列のみ)で、zshおよびと同じcolumn

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

(${(f)"$(<infile)"})配列の行を読み取ります。各要素の最初のフィールドを${(j;:;)list[@]%:*}(と:)結合し、各要素の2番目のフィールドを${(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出力が一時ファイルのように表示されます。したがって、cat2つのファイルを連結し、それをさらにパイプします。

    • コマンド1head -n 11 virtual.txt | cut -d: -f1、私たちの将来の列ヘッダを与えます。1つの仮想マシンエントリは最初の11行で、headコマンドを使用して取得します。はcutこのエントリを2つの列に分割し、最初の列だけを出力します。
    • コマンド2sed 's/.*: //' virtual.txt-将来の列の値を提供します。sed不要なテキストをすべて削除し、値のみを残します。
  2. xargs -d '\n' -n 11。各入力項目は改行で終了します。このコマンドはアイテムを取得し、1行あたり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行の(タブ)文字の数をマッサージする必要がある場合があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.