แปลงแถวเป็นคอลัมน์


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 ของ VMs)

เราจำเป็นต้องได้รับรายละเอียดนี้ในรูปแบบด้านล่างโดยใช้ 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

2
การทำซ้ำแถวที่เป็น
αғsнιη

คำตอบ:


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 เป็นคำตอบที่ดีที่สุด One pass สั้นที่สุดเท่าที่มีฟิลด์จะพิมพ์ชื่อฟิลด์ส่วนหัว awk pass ถัดไปจะพิมพ์เฉพาะฟิลด์ 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 (และตระกูลเดเบียน) ด้วย:

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:ล้างเอาต์พุตโดยไม่คำนึงถึง (มีบรรทัดว่างในอินพุตดั้งเดิมที่ระบุในคำถาม แต่ตั้งแต่นั้นถูกลบออกไปคำสั่งด้านบนทำงานโดยไม่คำนึงถึงบรรทัดว่าง)

อินพุต - เนื้อหาของไฟล์ชื่อ "อินพุต" ในคำสั่งด้านบน:

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


เปลี่ยนคำตอบเป็นแบบไดนามิก เพียงแค่ต้องการข้อมูล VM ต่อ 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ให้ส่วนหัวคอลัมน์ในอนาคตกับเรา รายการ Virtual Machine หนึ่งรายการเป็นสิบเอ็ดบรรทัดแรก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บรรทัดหากค่าตัวแปรของคุณมีความยาวแตกต่างกัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.