Перетворити рядки в стовпці


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. Наведений вище файл є лише прикладом гіпервізора, коли у нас працює лише 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

Відповіді:


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

EDIT: Розширюється на будь-яку кількість вихідних рядків у простому 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:і очищення виводу незалежно. (На початковому введенні, зазначеному в запитанні, були порожні рядки, але вони з тих пір були видалені. Наведена вище команда працює незалежно від порожніх рядків.)

Введення - вміст файлу з назвою "введення" у наведеній вище команді:

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 VM даних.
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.