Chuyển đổi hàng thành cột


10

Tôi có một tệp bao gồm các chi tiết về máy ảo đang chạy trong một trình ảo hóa. Chúng tôi chạy một số lệnh và chuyển hướng đầu ra đến một tập tin. Và dữ liệu có sẵn ở định dạng dưới đây.

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

Đầu ra này khác với hypanneror so với hypanneror vì trên một số hypanneror chúng ta có 50 + vms đang chạy. Tệp ở trên chỉ là một ví dụ từ nhà ảo thuật, nơi chúng tôi chỉ có 3 máy ảo đang chạy và do đó tệp được chuyển hướng dự kiến ​​sẽ chứa thông tin về một số (số N máy ảo)

Chúng ta cần lấy chi tiết này ở định dạng dưới đây bằng awk / sed hoặc với tập lệnh 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
Bản sao có thể có của Hàng chuyển sang cột của tệp
αғsнιη

Câu trả lời:


1

Nếu đi bộ tệp hai lần không phải là vấn đề (lớn) (sẽ chỉ lưu trữ một dòng trong bộ nhớ):

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

Trong đó, đối với tổng số trường sẽ là (có thể có nhiều bước của tệp):

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

Nhưng đối với một chuyển vị thực sự chung, điều này sẽ hoạt động:

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

Và để làm cho nó đẹp (sử dụng tab \tlàm dấu tách trường):

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

Mã ở trên cho một chuyển đổi chung sẽ lưu trữ toàn bộ ma trận trong bộ nhớ.
Đó có thể là một vấn đề cho các tập tin thực sự lớn.


Cập nhật cho văn bản mới.

Để xử lý văn bản mới được đăng trong câu hỏi, có vẻ như với tôi rằng hai pass awk là câu trả lời tốt nhất. Một lượt, ngắn như các trường tồn tại, sẽ in tiêu đề trường tiêu đề. Pass awk tiếp theo sẽ chỉ in trường 2. Trong cả hai trường hợp, tôi đã thêm một cách để loại bỏ khoảng trắng hàng đầu và dấu (để định dạng tốt hơn).

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

Xung quanh { ... } | column -t -s "$(printf '%b' '\t')"là định dạng toàn bộ bảng theo một cách khá hay.
Xin lưu ý rằng "$(printf '%b' '\t')"có thể được thay thế bằng $'\t'ksh, bash hoặc zsh.


8

Nếu bạn có rstiện ích (định hình lại) có sẵn, bạn có thể làm như sau:

rs -Tzc: < input.txt

Điều này cung cấp định dạng đầu ra chính xác như được chỉ định trong câu hỏi, thậm chí xuống đến độ rộng cột động.

  • -T Chuyển dữ liệu đầu vào
  • -z kích thước các cột một cách thích hợp từ mức tối đa trong mỗi cột
  • -c: sử dụng dấu hai chấm làm dấu tách trường đầu vào

Điều này làm việc cho các bảng có kích thước tùy ý, ví dụ:

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

rscó sẵn theo mặc định trên OS X (và có thể là các máy BSD khác). Nó có thể được cài đặt trên Ubuntu (và họ debian) với:

sudo apt-get install rs

6

EDIT: Có thể mở rộng cho bất kỳ số lượng hàng đầu ra nào, trong một forvòng lặp một lớp đơn giản :

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

Câu trả lời gốc:

Bạn có thể làm điều này như một lớp lót bằng cách sử dụng bashthay thế quy trình:

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

Các -stùy chọn để pastelàm cho nó xử lý mỗi một tập tin tại một thời điểm. Dấu :phân cách được đặt trong paste"bị bắt" bởi -stùy chọn columnở cuối, để làm đẹp định dạng bằng cách làm cho các trường thẳng hàng.

Các cutlệnh trong hai thay thế quá trình lần lượt kéo ra trường thứ nhất và trường thứ hai.

Cho dù có dòng trống trong đầu vào hay không không quan trọng, vì column -t -s:sẽ làm sạch đầu ra bất kể. (Có các dòng trống trong đầu vào ban đầu được chỉ định trong câu hỏi, nhưng chúng đã bị xóa. Lệnh trên hoạt động bất kể các dòng trống.)

Đầu vào - nội dung của tệp có tên "đầu vào" trong lệnh trên:

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

Đầu ra:

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
Điều này hoạt động cho hai hàng đầu ra, nhưng đối với nhiều hàng hơn, nó trở nên khó tin.

2

Sử dụng awk, lưu trữ khóa và giá trị và in chúng ra cuối cùng.

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

Chỉ cần chạy awk -f ./script.awk ./input.txt


Thay đổi câu trả lời để năng động. Chỉ cần yêu cầu dữ liệu chỉ có 1 VM cho mỗi tệp.
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

Với gnu datamashcolumntừ util-linux:

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

Điều này hoạt động với hơn hai cột nhưng giả sử không có dòng trống trong tệp đầu vào của bạn; với các dòng trống ở giữa (như trong mẫu đầu vào ban đầu của bạn), bạn sẽ gặp một lỗi như:

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

Vì vậy, để tránh điều đó, bạn sẽ phải ép chúng trước khi xử lý datamash:

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

Mặt khác, trong trường hợp cụ thể này (chỉ có hai cột), có zshvà giống nhau column:

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

(${(f)"$(<infile)"})đọc các dòng trong một mảng; ${(j;:;)list[@]%:*}tham gia (với :) trường đầu tiên của mỗi phần tử và ${(j;:;)list[@]#*:}tham gia (một lần nữa với :) trường thứ hai của mỗi phần tử; cả hai đều được in, ví dụ như đầu ra là

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

mà sau đó được dẫn đến column -t -s:


0

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

Số lượng dòng trên mỗi Máy ảo được mã hóa cứng trong trường hợp này - 11. Sẽ tốt hơn khi đếm nó trước và lưu vào biến, sau đó sử dụng biến này trong mã.

Giải trình

  1. cat <(command 1) <(command 2)- <()xây dựng làm cho commandđầu ra xuất hiện như một tập tin tạm thời. Do đó, catnối hai tập tin và ống nó hơn nữa.

    • lệnh 1 : head -n 11 virtual.txt | cut -d: -f1, cho chúng ta các tiêu đề cột trong tương lai. Một mục nhập Máy ảo là mười một dòng đầu tiên, headlệnh được sử dụng để có được nó. Việc cutchia mục này thành hai cột và in cột đầu tiên.
    • lệnh 2 : sed 's/.*: //' virtual.txt- cung cấp cho chúng ta các giá trị cột trong tương lai. sedxóa tất cả văn bản không cần thiết và chỉ để lại các giá trị.
  2. xargs -d '\n' -n 11. Mỗi mục đầu vào được kết thúc bởi dòng mới. Lệnh này nhận các mục và in chúng 11 lần trên mỗi dòng.

  3. column -t- là cần thiết cho màn hình in ấn đẹp. Nó hiển thị các dòng của chúng tôi trong một hình thức bảng. Nếu không, mỗi dòng sẽ có chiều rộng khác nhau.

Đầu ra

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

Sử dụng datamashtransposetùy chọn của nó để trao đổi các hàng và cột trong một tệp.

datamash -t: transpose < infile.txt

Theo mặc định, transpose xác minh đầu vào có cùng số lượng trường trong mỗi dòng và không có lỗi nếu không và bạn có thể vô hiệu hóa chế độ nghiêm ngặt của nó để cho phép các giá trị bị thiếu bằng cách --no-strict

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

Ngoài ra, bạn có thể sử dụng --fillerđể đặt giá trị điền vào trường bị thiếu:

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

có nguồn gốc từ datamash manual


-5

nếu dữ liệu của bạn nằm trong các tệp riêng biệt trong một thư mục, bạn có thể sử dụng:

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

bạn có thể cần phải xoa bóp số lượng \t(tab) ký tự trên printfdòng nếu các giá trị biến của bạn có độ dài khác nhau.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.