シェル/パールスクリプトを使用して次の形式で出力したいデータがあります。
データ:
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
これらの問題を解決するために設計および製造されています。 「病弱な折衷主義ゴミリスト」というニックネームがついた。
に関する記事を読んでください。実装する。ユーザーがする必要があるのは、データを読み取って(一度に1行ずつ)、解析して変数に入力し、定義したデータに基づいて現在の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)
.
データを取得する方法はよくわかりませんが、2つの改行で区切られたファイルに保存するとします。各ホストは行ブロックです。
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;
}