Конвертировать строки в столбцы


10

У меня есть файл, который содержит информацию о виртуальных машинах, работающих в гипервизоре. Мы запускаем некоторую команду и перенаправляем вывод в файл. И данные доступны в следующем формате.

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. Выше файл является просто примером из гипервизора, где у нас работает только 3 виртуальные машины, и, следовательно, перенаправленный файл должен содержать информацию о нескольких (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

Ответы:


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 - лучший ответ. Один проход, так как поля существуют, напечатает заголовки полей заголовка. При следующем проходе 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')"можно заменить $'\t'на ksh, bash или zsh.


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
$ 

rsдоступно по умолчанию на OS 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делает его обрабатывать каждый файл по одному. Установленный :разделитель paste«пойман» -sопцией columnв конце, чтобы привести в порядок формат, выровняв поля.

Эти cutкоманды в двух технологических замен вытащить первое поле и второе поле, соответственно.

Есть ли пустые строки на входе или нет, не имеет значения, так как column -t -s:очистит вывод независимо. (В исходном вводе, указанном в вопросе, были пустые строки, но с тех пор они были удалены. Приведенная выше команда работает независимо от пустых строк.)

Input - содержимое файла с именем «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

Используя 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 ВМ данных.
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

С gnu datamashи columnиз util-linux:

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

Это работает с более чем двумя столбцами, но предполагает, что во входном файле нет пустых строк; с пустыми строками между ними (как в исходном входном примере) вы получите ошибку вроде:

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

так что во избежание этого вам придется сжать их перед обработкой datamash:

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

В противном случае, в данном конкретном случае (только два столбца), с zshи одинаковыми column:

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

(${(f)"$(<infile)"})читает строки в массиве; ${(j;:;)list[@]%:*}объединяет (с :) первое поле каждого элемента и ${(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вывод похожим на временный файл. Следовательно, catобъединяет два файла и передает его дальше.

    • Команда 1 : head -n 11 virtual.txt | cut -d: -f1дает нам будущие заголовки столбцов. Одна запись виртуальной машины состоит из первых одиннадцати строк, headдля ее получения используется команда. cutРазделяет эту запись на две колонки и напечатать только первый.
    • Команда 2 : sed 's/.*: //' virtual.txt- дает нам будущие значения столбца. sedудаляет весь ненужный текст и оставляет только значения.
  2. xargs -d '\n' -n 11, Каждый элемент ввода завершается символом новой строки. Эта команда получает элементы и печатает их по 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строке, если значения переменных имеют разную длину.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.