Converti le righe in colonne


10

Ho un file che include dettagli sulle macchine virtuali in esecuzione in un hypervisor. Eseguiamo alcuni comandi e reindirizziamo l'output su un file. E i dati sono disponibili nel formato seguente.

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

Questo output differisce da hypervisor a hypervisor poiché su alcuni hypervisor abbiamo 50 + vms in esecuzione. Il file sopra è solo un esempio dell'hypervisor in cui abbiamo solo 3 VM in esecuzione e quindi il file reindirizzato dovrebbe contenere informazioni su diversi (N numero di VM)

Dobbiamo ottenere questi dettagli nel formato seguente usando awk / sed o con uno script di 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

2
Possibile duplicato della conversione del file
αғsнιη

Risposte:


1

Se camminare due volte il file non è un problema (grande) (memorizzerà solo una riga in memoria):

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

Quale, per un conteggio generale dei campi sarebbe (che potrebbe avere molte passeggiate del file):

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

Ma per un recepimento veramente generale, questo funzionerà:

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

E per renderlo carino (usando la tab \tcome separatore di campo):

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

Il codice sopra per una trasposizione generale memorizzerà l'intera matrice in memoria.
Potrebbe essere un problema per file di grandi dimensioni.


Aggiornamento per nuovo testo.

Per elaborare il nuovo testo pubblicato nella domanda, mi sembra che due passaggi di awk siano la risposta migliore. Un passaggio, per quanto brevi siano i campi, stampa i titoli dei campi di intestazione. Il prossimo passaggio awk stamperà solo il campo 2. In entrambi i casi, ho aggiunto un modo per rimuovere gli spazi iniziali e finali (per una migliore formattazione).

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

L'ambiente circostante { ... } | column -t -s "$(printf '%b' '\t')"è di formattare l'intero tavolo in modo carino.
Nota che "$(printf '%b' '\t')"potrebbe essere sostituito con $'\t'in ksh, bash o zsh.


8

Se si dispone rsdell'utilità (rimodella) disponibile, è possibile effettuare le seguenti operazioni:

rs -Tzc: < input.txt

Ciò fornisce il formato di output esattamente come specificato nella domanda, anche fino alle larghezze dinamiche della colonna.

  • -T Traspone i dati di input
  • -z dimensiona le colonne in modo appropriato dal massimo in ogni colonna
  • -c: usa i due punti come separatore del campo di input

Funziona con tabelle di dimensioni arbitrarie, ad esempio:

$ 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è disponibile per impostazione predefinita su OS X (e probabilmente su altre macchine BSD). Può essere installato su Ubuntu (e famiglia Debian) con:

sudo apt-get install rs

6

EDIT: estendibile a qualsiasi numero di righe di output, in un semplice forciclo di una riga :

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

Risposta originale:

Puoi farlo come una linea usando la bashsostituzione del processo:

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

L' -sopzione per pastefarlo gestire ogni file uno alla volta. Il :delimitatore impostato pasteviene "catturato" -sdall'opzione alla columnfine, per rendere il formato più semplice allineando i campi.

I cutcomandi nelle due sostituzioni di processo estraggono rispettivamente il primo campo e il secondo campo.

Indipendentemente dal fatto che ci siano o meno righe vuote nell'input, non importa quale column -t -s:sarà l'output. (C'erano linee vuote nell'input originale specificato nella domanda, ma da allora sono state rimosse. Il comando sopra funziona indipendentemente dalle linee vuote.)

Input: contenuto del file denominato "input" nel comando precedente:

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

Produzione:

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
Questo funziona per due righe di output, ma per più righe diventa poco maneggevole.

2

Usando awk, memorizza la chiave e il valore e stampali alla fine.

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

La corsa giusta awk -f ./script.awk ./input.txt


Modificata la risposta in dinamica. Richiede solo che vi sia solo 1 VM di dati per file.
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

Con gnu datamashe columnda util-linux:

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

Funziona con più di due colonne ma presuppone che non ci siano righe vuote nel file di input; con le righe vuote tra (come nell'esempio di input iniziale) si otterrebbe un errore come:

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

quindi per evitare di doverli spremere prima dell'elaborazione con datamash:

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

Altrimenti, in questo caso particolare (solo due colonne), con zshe lo stesso column:

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

(${(f)"$(<infile)"})legge le righe in un array; ${(j;:;)list[@]%:*}unisce (con :) il primo campo di ciascun elemento e ${(j;:;)list[@]#*:}unisce (di nuovo con :) il secondo campo di ciascun elemento; questi sono entrambi stampati, ad esempio l'output è

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

che viene quindi convogliato a column -t -s:


0

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

In questo caso il numero di righe per macchina virtuale è hardcoded - 11. Sarà meglio contarlo in anticipo e memorizzarlo nella variabile, quindi utilizzare questa variabile nel codice.

Spiegazione

  1. cat <(command 1) <(command 2)- la <()costruzione fa commandapparire l'output come un file temporaneo. Pertanto, catconcatena due file e lo convoglia ulteriormente.

    • 1 Comando : head -n 11 virtual.txt | cut -d: -f1, ci dà futuri intestazioni delle colonne. L'unica voce della macchina virtuale è le prime undici righe, il headcomando viene utilizzato per ottenerlo. Il cutdivide questa voce a due colonne e stampare l'unico primo.
    • comando 2 : sed 's/.*: //' virtual.txt- ci fornisce valori di colonna futuri. sedrimuove tutto il testo non necessario e lascia solo valori.
  2. xargs -d '\n' -n 11. Ogni elemento di input viene terminato da newline. Questo comando ottiene elementi e li stampa di 11 per riga.

  3. column -t- è necessario per display piuttosto carini. Visualizza le nostre linee in una tabella. Altrimenti, ogni linea avrà una larghezza diversa.

Produzione

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

Utilizzare datamashe la sua transposeopzione per scambiare righe e colonne in un file.

datamash -t: transpose < infile.txt

Per impostazione predefinita, trasposizione verifica che l'input abbia lo stesso numero di campi in ogni riga e non riesce con un errore altrimenti e puoi disabilitare la sua modalità rigorosa per consentire valori mancanti --no-strict

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

Inoltre è possibile utilizzare --fillerper impostare il valore di riempimento del campo mancante:

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

derivato da datamash manual


-5

se i tuoi dati sono in file separati in una directory, puoi usare:

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

potrebbe essere necessario massaggiare il numero di caratteri \t(tab) sulla printfriga se i valori delle variabili hanno lunghezze diverse.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.