쉘/펄 스크립트를 사용하여 다음 형식으로 출력하려는 일부 데이터가 있습니다.
데이터:
Virtual Machine Test status Running.
Assigned Server OVS001.local
Virtual Disk Test_DISK1 (30) size 61GB
Physical Disk HITACHI (110)
Physical Disk HITACHI (113)
Physical Disk HITACHI (111)
원하는 출력:
Virtual_Machine Vdsks size Physical_Disks
Test Test_DISK1 61GB -
Test - - HITACHI (110)
Test - - HITACHI (113)
Test - - HITACHI (111)
이를 위해서는 여러 가상 머신을 가져와야 합니다.
답변1
perl
이러한 문제를 해결하기 위해 설계 및 제조되었습니다. "병약한 절충주의 쓰레기 목록"이라는 별명이 붙었습니다.
에 관한 문서를 읽어보세요.구현하다. 사용자가 해야 할 일은 데이터를 읽고(예: 한 번에 한 줄씩) 구문 분석하고 변수에 채운 다음 정의한 데이터를 write
기반으로 현재 데이터를 출력하는 명령을 실행하는 것뿐입니다.format
데이터의 헤더 형식은 다음과 같습니다.
format STDOUT_TOP =
Virtual_Machine Vdsks size Physical_Disks
----------------- ------------------ --------- ---------------
.
각 출력 라인마다 또 다른 것이 있습니다:
format STDOUT =
@<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<< @>>>>>>>>>>> -
$virtualmachine, @vdisk, @vdisk_size
@<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<~~ @>>>>>>>>>~~ -
$#vdisk<0?'':$virtualmachine, shift(@vdisk), shift(@vdisk_size)
@<<<<<<<<<<<<<<<< - ^<<<<<<<<<<<<~~
$#disks<0?'':$virtualmachine, shift(@disks)
.
데이터를 어떻게 얻는지는 잘 모르겠지만 두 개의 줄 바꿈으로 구분된 파일에 저장한다고 가정해 보겠습니다. 각 호스트는 행 블록입니다.
Virtual Machine Test1 status Running.
Assigned Server OVS001.local
Virtual Disk Test_DISK1 (30) size 61GB
Physical Disk HITACHI (110)
Physical Disk HITACHI (113)
Physical Disk HITACHI (111)
Virtual Machine Test status Running.
Assigned Server OVS002.local
Virtual Disk Test_DISK1 (30) size 41GB
Physical Disk HITACHI (110)
Physical Disk HITACHI (113)
Physical Disk HITACHI (111)
입력 구분 기호를 다음과 같이 설정할 수 있습니다.
$/="\n\n";
읽을 때마다 전체 텍스트 블록, 즉 가상 호스트의 모든 행을 얻게 됩니다.
while (<>) {
# process one virtual machine
}
이제 재미있는 일이 시작됩니다. 입력을 구문 분석하는 것입니다. while 루프 내에서 다음을 수행할 수 있습니다.
my @lines=split("\n");
local @disks=(); # initialize
local $virtualmachine="unknown";
local $physicalserver="unknown";
local @vdisk=("unknown");
local @vdisk_size=("unknown");
foreach (@lines) {
$virtualmachine = $1 if /^Virtual Machine\s+(\S+)\s+status\s+/;
$physicalserver = $1 if /^Assigned Server\s+(\S+)/;
do { push @vdisk,$1; push @vdisk_size,$2; }
if /^Virtual Disk\s+(\S+).* size\s+(\d+\w+)/;
push @disks,$1 if /^Physical Disk\s+(.*)/;
}
write;
구문 분석은 조잡하지만 일반적으로 효과적입니다.
답변2
서식을 얼마나 정확하게 지정하느냐에 따라 다르지만 일반적으로 탭으로 구분하면 충분하지만 저는 다음과 같이 접근합니다.
#!/usr/bin/env perl
use strict;
use warnings;
#set record separator to double line feed.
local $/ = "\n\n";
#print header row
print join "\t", "VM", "Virtual_Disk", "size", "Physical Disks", "\n";
#iterate stdin or files specified on command line
while ( <> ) {
#capture data from this 'chunk':
my ( $vm ) = /Virtual Machine\s+(\w+)/;
my ( $status ) = /status\s*(\w+)/;
my @physical_disks = m/Physical Disk\s+(.*)/g;
my %virtual_disks = m/Virtual Disk\s+(\w+).*size\s+(\w+)/g;
#output tab separated
print join ("\t", $vm, $_, $virtual_disks{$_}, "-" ), "\n" for keys %virtual_disks;
print join ("\t", $vm, "-", "-", $_ ), "\n" for @physical_disks;
}
이는 고정 너비 자체가 아닌 탭 정지에 맞춰 정렬됩니다. 사용 사례에 따라 이 방법이 더 적합할 수 있습니다. 그렇지 않은 경우 - format
위와 같이 사용하거나 sprintf
고정 필드 너비를 사용할 수 있습니다.
#!/usr/bin/env perl
use strict;
use warnings;
local $/ = "\n\n";
my $field_format = "%8s"; #string, 8 chars wide
print join "\t", map { sprintf $field_format, $_ } "VM", "Virtual_Disk", "size", "Physical Disks", "\n";
while ( <> ) {
my ( $vm ) = /Virtual Machine\s+(\w+)/;
my ( $status ) = /status\s*(\w+)/;
my @physical_disks = m/Physical Disk\s+(.*)/g;
my %virtual_disks = m/Virtual Disk\s+(\w+).*size\s+(\w+)/g;
print join "\t", map { sprintf $field_format, $_} ( $vm, $_, $virtual_disks{$_}, "-" ), "\n" for keys %virtual_disks;
print join "\t", map { sprintf $field_format, $_} ( $vm, "-", "-", $_ ), "\n" for @physical_disks;
}