행을 열로 변환

행을 열로 변환

하이퍼바이저에서 실행되는 가상 머신에 대한 세부 정보가 포함된 파일이 있습니다. 몇 가지 명령을 실행하고 출력을 파일로 리디렉션합니다. 데이터는 다음 형식일 수 있습니다.

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개가 넘는 VM을 실행하는 일부 하이퍼바이저에서는 이 출력이 하이퍼바이저에 따라 다릅니다. 위 파일은 3개의 VM만 실행하는 하이퍼바이저의 예일 뿐이므로 리디렉션된 파일에는 여러(N개의 VM)에 대한 정보가 포함될 것으로 예상됩니다.

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

당신이 가지고 있다면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
$ 

rsOS X(및 기타 BSD 시스템)에서 기본적으로 사용 가능합니다. 다음 명령을 사용하여 Ubuntu(및 debian 시리즈)에 설치할 수 있습니다.

sudo apt-get install rs

답변2

편집하다:간단한 한 줄 루프 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필드를 정렬하여 서식을 아름답게 만드는 마지막 옵션에 의해 "캡처"됩니다.-scolumn

두 프로세스 대체의 명령은 cut각각 첫 번째 필드와 두 번째 필드를 가져옵니다.

입력에 빈 줄이 있어도 상관없습니다. column -t -s:어쨌든 출력이 삭제되기 때문입니다. (질문에 지정된 원래 입력에는 빈 줄이 있었지만 제거되었습니다. 위 명령은 빈 줄에 관계없이 작동합니다.)

입력 - 위 명령에서 "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

답변3

파일을 두 번 탐색하는 것이 (큰) 문제가 아닌 경우(한 행만 메모리에 저장됩니다):

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')"ksh, bash 또는 zsh로 대체될 수 있습니다.$'\t'

답변4

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

관련 정보