Konvertieren Sie Zeilen in Spalten


10

Ich habe eine Datei, die Details zu VMs enthält, die in einem Hypervisor ausgeführt werden. Wir führen einen Befehl aus und leiten die Ausgabe in eine Datei um. Und die Daten sind im folgenden Format verfügbar.

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

Diese Ausgabe unterscheidet sich von Hypervisor zu Hypervisor, da auf einigen Hypervisoren mehr als 50 VMS ausgeführt werden. Die obige Datei ist nur ein Beispiel aus dem Hypervisor, in dem nur 3 VMs ausgeführt werden. Daher wird erwartet, dass die umgeleitete Datei Informationen zu mehreren enthält (N Anzahl von VMs).

Wir müssen diese Details im folgenden Format mit awk / sed oder mit einem Shell-Skript erhalten

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

Antworten:


1

Wenn das zweimalige Durchlaufen der Datei kein (großes) Problem darstellt (speichert nur eine Zeile im Speicher):

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

Was für eine allgemeine Anzahl von Feldern wäre (was viele Durchgänge der Datei haben könnte):

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

Aber für eine wirklich allgemeine Transponierung wird dies funktionieren:

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

Und um es hübsch zu machen (mit Tab \tals Feldtrennzeichen):

./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

Der obige Code für eine allgemeine Transponierung speichert die gesamte Matrix im Speicher.
Das könnte ein Problem für wirklich große Dateien sein.


Update für neuen Text.

Um den neuen Text in der Frage zu verarbeiten, scheint es mir, dass zwei Durchgänge von awk die beste Antwort sind. Ein Durchgang, so kurz wie Felder vorhanden sind, druckt die Titel der Kopfzeilenfelder. Der nächste awk-Durchgang gibt nur Feld 2 aus. In beiden Fällen habe ich eine Möglichkeit hinzugefügt, führende und nachfolgende Leerzeichen zu entfernen (zur besseren Formatierung).

#!/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')"

Die Umgebung { ... } | column -t -s "$(printf '%b' '\t')"soll die gesamte Tabelle auf hübsche Weise formatieren.
Bitte beachten Sie, dass die "$(printf '%b' '\t')"ersetzt werden könnte , mit $'\t'in ksh, bash oder zsh.


8

Wenn Sie das rsDienstprogramm (Umformen) zur Verfügung haben, können Sie Folgendes tun:

rs -Tzc: < input.txt

Dadurch wird das Ausgabeformat bis auf die dynamischen Spaltenbreiten genau wie in der Frage angegeben angegeben.

  • -T Transponiert die Eingabedaten
  • -z Größe der Spalten entsprechend dem Maximum in jeder Spalte
  • -c: verwendet Doppelpunkt als Eingabefeldtrennzeichen

Dies funktioniert für Tabellen beliebiger Größe, z.

$ 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
$ 

rsist standardmäßig unter OS X (und wahrscheinlich auch auf anderen BSD-Computern) verfügbar. Es kann unter Ubuntu (und der Debian-Familie) installiert werden mit:

sudo apt-get install rs

6

EDIT: Erweiterbar auf eine beliebige Anzahl von Ausgabezeilen in einer einfachen Einzeiler- forSchleife:

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

Ursprüngliche Antwort:

Sie können dies als Einzeiler mithilfe der bashProzessersetzung tun :

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

Die -sOption, pastejede Datei einzeln zu verarbeiten. Das eingesetzte :Trennzeichen pastewird durch die -sOption " columnam Ende " "abgefangen" , um das Format durch Anordnen der Felder zu verbessern.

Die cutBefehle in den beiden Prozessersetzungen ziehen das erste Feld bzw. das zweite Feld heraus.

Ob die Eingabe Leerzeilen enthält oder nicht, spielt keine Rolle, da column -t -s:die Ausgabe unabhängig davon bereinigt wird. (Die in der Frage angegebene ursprüngliche Eingabe enthielt Leerzeilen, die jedoch inzwischen entfernt wurden. Der obige Befehl funktioniert unabhängig von Leerzeilen.)

Eingabe - Inhalt der Datei mit dem Namen "Eingabe" im obigen Befehl:

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

Ausgabe:

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
Dies funktioniert für zwei Ausgabezeilen, für weitere Zeilen wird es jedoch unhandlich.

2

Speichern Sie mit awk den Schlüssel und den Wert und drucken Sie sie am Ende aus.

#!/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]
  }

Die laufen einfach awk -f ./script.awk ./input.txt


Die Antwort wurde in "Dynamisch" geändert. Es ist nur erforderlich, dass nur 1 VM-Daten pro Datei vorhanden sind.
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

Mit gnu datamashund columnvon util-linux:

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

Dies funktioniert mit mehr als zwei Spalten, setzt jedoch voraus, dass Ihre Eingabedatei keine Leerzeilen enthält. Mit leeren Zeilen dazwischen (wie in Ihrem ersten Eingabebeispiel) erhalten Sie eine Fehlermeldung wie:

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

Um zu vermeiden, dass Sie sie vor der Verarbeitung mit datamashfolgenden Elementen zusammendrücken müssen :

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

Andernfalls in diesem speziellen Fall (nur zwei Spalten) mit zshund dasselbe column:

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

(${(f)"$(<infile)"})liest die Zeilen in einem Array; ${(j;:;)list[@]%:*}verbindet (mit :) das erste Feld jedes Elements und ${(j;:;)list[@]#*:}verbindet (wieder mit :) das zweite Feld jedes Elements; diese werden beide gedruckt, zB die Ausgabe ist

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

welches dann zu geleitet wird column -t -s:


0

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

Die Anzahl der Zeilen pro virtueller Maschine ist in diesem Fall fest codiert - 11. Zählen Sie sie besser vorher und speichern Sie sie in der Variablen. Verwenden Sie dann diese Variable im Code.

Erläuterung

  1. cat <(command 1) <(command 2)- Die <()Konstruktion lässt die commandAusgabe wie eine temporäre Datei erscheinen. Daher catverkettet zwei Dateien und Pipes es weiter.

    • Befehl 1 : head -n 11 virtual.txt | cut -d: -f1, gibt uns zukünftige Spaltenüberschriften. Der eine Eintrag für eine virtuelle Maschine besteht aus den ersten elf Zeilen. Der headBefehl wird verwendet, um ihn abzurufen. Das cutteilt diesen Eintrag in zwei Spalten auf und druckt die einzige erste.
    • Befehl 2 : sed 's/.*: //' virtual.txt- gibt uns zukünftige Spaltenwerte. sedEntfernt den gesamten nicht benötigten Text und hinterlässt nur Werte.
  2. xargs -d '\n' -n 11. Jedes Eingabeelement wird durch einen Zeilenumbruch beendet. Dieser Befehl ruft Elemente ab und druckt sie mit 11 pro Zeile.

  3. column -t- wird für hübsch gedruckte Displays benötigt. Es zeigt unsere Zeilen in Tabellenform an. Andernfalls hat jede Linie eine andere Breite.

Ausgabe

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

Verwenden Sie datamashund seine transposeOption, um Zeilen und Spalten in einer Datei auszutauschen.

datamash -t: transpose < infile.txt

Standardmäßig überprüft transponieren, ob die Eingabe die gleiche Anzahl von Feldern in jeder Zeile enthält, und schlägt ansonsten mit einem Fehler fehl. Sie können den strengen Modus deaktivieren, um fehlende Werte durch zuzulassen --no-strict

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

Sie können auch den Füllwert --fillerfür fehlende Felder festlegen:

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

abgeleitet von datamash manual


-5

Wenn sich Ihre Daten in separaten Dateien in einem Verzeichnis befinden, können Sie Folgendes verwenden:

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

Möglicherweise müssen Sie die Anzahl der \t(Tab-) Zeichen in der printfZeile massieren , wenn Ihre variablen Werte unterschiedlich lang sind.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.