Konwertuj wiersze na kolumny

10

Mam plik, który zawiera szczegółowe informacje na temat maszyn wirtualnych działających w hiperwizorze. Wykonujemy polecenie i przekierowujemy dane wyjściowe do pliku. A dane są dostępne w poniższym formacie.

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

Ta informacja wyjściowa różni się od hiperwizora do hiperwizora, ponieważ na niektórych hiperwizorach mamy uruchomionych ponad 50 vms. Powyższy plik jest tylko przykładem hiperwizora, w którym mamy tylko 3 maszyny wirtualne, a zatem przekierowany plik powinien zawierać informacje o kilku (liczba N maszyn wirtualnych)

Musimy uzyskać te szczegóły w poniższym formacie za pomocą awk / sed lub skryptu powłoki

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
IgniteLX
źródło
2
Możliwy duplikat konwersji wierszy do kolumny pliku
αғsнιη

Odpowiedzi:

1

Jeśli dwukrotne przejście pliku nie stanowi (dużego) problemu (zapisze tylko jedną linię w pamięci):

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

Który dla ogólnej liczby pól byłby (który może mieć wiele spacerów po pliku):

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

Ale w przypadku naprawdę ogólnej transpozycji będzie to działać:

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

I aby było ładnie (używając tab \tjako separatora pól out):

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

Powyższy kod ogólnej transpozycji zapisze całą macierz w pamięci.
Może to stanowić problem w przypadku naprawdę dużych plików.


Zaktualizuj nowy tekst.

Aby przetworzyć nowy tekst zamieszczony w pytaniu, Wydaje mi się, że najlepszą odpowiedzią są dwa przejścia awk. Jedno przejście, o ile istnieją pola, spowoduje wydrukowanie tytułów pól nagłówka. Następne przejście do awk wyświetli tylko pole 2. W obu przypadkach dodałem sposób usuwania spacji początkowych i końcowych (dla lepszego formatowania).

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

Otoczenie { ... } | column -t -s "$(printf '%b' '\t')"ma sformatować cały stół w ładny sposób.
Pamiętaj, że "$(printf '%b' '\t')"można je zastąpić $'\t'w ksh, bash lub zsh.


źródło
8

Jeśli masz dostępne rsnarzędzie (przekształć) , możesz wykonać następujące czynności:

rs -Tzc: < input.txt

Daje to format wyjściowy dokładnie taki, jak określono w pytaniu, nawet do dynamicznych szerokości kolumn.

  • -T Transponuje dane wejściowe
  • -z dopasowuje kolumny odpowiednio do maksimum w każdej kolumnie
  • -c: używa dwukropka jako separatora pola wejściowego

Działa to w przypadku tabel o dowolnym rozmiarze, np .:

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

rsjest domyślnie dostępny na OS X (i prawdopodobnie na innych maszynach BSD). Może być zainstalowany na Ubuntu (i rodzinie Debiana) z:

sudo apt-get install rs
Cyfrowa trauma
źródło
6

EDYCJA: Rozszerzalna na dowolną liczbę wierszy wyjściowych, w prostej forpętli jednowierszowej :

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

Oryginalna odpowiedź:

Możesz to zrobić jako jedno-liniowy przy użyciu bashpodstawienia procesu:

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

-sOpcja pastepozwala obsłużyć każdy plik na raz. :Zestaw separatora pastejest „złapany” przez -sopcją columnna końcu, aby całkiem się formatem poprzez pola kolejce.

Te cutpolecenia w dwa podstawniki procesu wyciągnąć pierwsze pole oraz drugie pole, odpowiednio.

To, czy na wejściu są puste linie, czy nie, nie ma znaczenia, niezależnie od tego, column -t -s:czy wyczyści dane wyjściowe. (W pierwotnym wejściu określonym w pytaniu były puste linie, ale zostały one usunięte. Powyższe polecenie działa niezależnie od pustych linii.)

Wejście - zawartość pliku o nazwie „wejście” w powyższym poleceniu:

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

Wynik:

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
Dzika karta
źródło
2
Działa to w przypadku dwóch wierszy wyjściowych, ale w przypadku większej liczby wierszy staje się niedziałające.
2

Korzystając z awk, zachowaj klucz i wartość i wydrukuj je na końcu.

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

Po prostu bieg awk -f ./script.awk ./input.txt

jecxjo
źródło
Zmieniono odpowiedź na dynamiczną. Wymaga tylko danych o wartości 1 VM na plik.
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
DopeGhoti
źródło
1

Z gnu datamashi columnod util-linux:

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

Działa to z więcej niż dwiema kolumnami, ale zakłada, że ​​w pliku wejściowym nie ma pustych linii; z pustymi wierszami pomiędzy (jak w początkowej próbce wejściowej), otrzymasz błąd taki jak:

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

aby uniknąć konieczności wyciśnięcia ich przed przetwarzaniem za pomocą datamash:

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

W przeciwnym razie, w tym konkretnym przypadku (tylko dwie kolumny), z zshtym samym column:

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

(${(f)"$(<infile)"})czyta linie w tablicy; ${(j;:;)list[@]%:*}łączy (z :) pierwszym polem każdego elementu i ${(j;:;)list[@]#*:}łączy (ponownie z :) drugim polem każdego elementu; oba są drukowane, np. wyjście jest

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

który jest następnie przesyłany do column -t -s:

don_crissti
źródło
0

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

W tym przypadku liczba wierszy na maszynę wirtualną jest zakodowana na stałe - 11. Lepiej policz ją wcześniej i zapisz w zmiennej, a następnie użyj tej zmiennej w kodzie.

Wyjaśnienie

  1. cat <(command 1) <(command 2)- <()konstrukcja sprawia, że commanddane wyjściowe wyglądają jak plik tymczasowy. Dlatego catkonkatenuje dwa pliki i potokuje je dalej.

    • polecenie 1 : head -n 11 virtual.txt | cut -d: -f1daje nam przyszłe nagłówki kolumn. Jedna pozycja maszyny wirtualnej to pierwsze jedenaście linii, headdo jej uzyskania służy polecenie. cutDzieli ten wpis do dwóch kolumnach i wydrukować tylko pierwszy z nich.
    • polecenie 2 : sed 's/.*: //' virtual.txt- podaje nam przyszłe wartości kolumn. sedusuwa cały niepotrzebny tekst i pozostawia tylko wartości.
  2. xargs -d '\n' -n 11. Każdy element wejściowy jest zakończony znakiem nowej linii. To polecenie pobiera elementy i drukuje je o 11 w wierszu.

  3. column -t- jest potrzebny do ładnych wydruków. Wyświetla nasze linie w formie tabeli. W przeciwnym razie każda linia będzie miała inną szerokość.

Wynik

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
MiniMax
źródło
0

Użyj datamashi jego transposeopcji, aby zamienić wiersze i kolumny w pliku.

datamash -t: transpose < infile.txt

Domyślnie transpozycja sprawdza, czy dane wejściowe mają taką samą liczbę pól w każdym wierszu, w przeciwnym razie kończy się błędem i można wyłączyć tryb ścisły, aby zezwolić na brakujące wartości --no-strict

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

Możesz także użyć --fillerdo ustawienia wartości pola brakującego pola:

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

pochodzi z datamash manual

αғsнιη
źródło
-5

jeśli twoje dane znajdują się w osobnych plikach w katalogu, możesz użyć:

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

może być konieczne masowanie liczby \t(tab) znaków w printfwierszu, jeśli wartości zmiennych mają różne długości.

MelBurslan
źródło