将文件中的数据读入数组以在Perl脚本中进行操作

时间:2018-05-27 18:54:33

标签: arrays perl file

Perl新手。我需要弄清楚如何从(:)分隔的文件中读取数组。然后我可以操纵数据。

以下是'serverFile.txt'文件的示例(只是随机扔了#) 这些字段是名称:CPU利用率:avgMemory用法:无磁盘

 Server1:8:6:2225410
 Server2:75:68:64392
 Server3:95:90:12806
 Server4:14:7:1548700

我想弄清楚如何将每个字段放入适当的数组然后执行函数。例如,找到具有最少可用磁盘空间的服务器。

我现在设置它的方式,我认为不会起作用。那么如何将每行中的每个元素放入一个数组中呢?

#!usr/bin/perl

use warnings;
use diagnostics;
use v5.26.1;

#Opens serverFile.txt or reports and error
open (my $fh, "<", "/root//Perl/serverFile.txt") 
    or die "System cannot find the file specified. $!";

#Prints out the details of the file format
sub header(){
    print "Server ** CPU Util% ** Avg Mem Usage ** Free Disk\n";
    print "-------------------------------------------------\n";
}

# Creates our variables
my ($name, $cpuUtil, $avgMemUsage, $diskFree);
my $count = 0;
my $totalMem = 0;
header();

# Loops through the program looking to see if CPU Utilization is greater than 90%
# If it is, it will print out the Server details
while(<$fh>) {
    # Puts the file contents into the variables
    ($name, $cpuUtil, $avgMemUsage, $diskFree) = split(":", $_);
    print "$name **  $cpuUtil% ** $avgMemUsage% ** $diskFree% ", "\n\n", if $cpuUtil > 90;
    $totalMem = $avgMemUsage + $totalMem;
    $count++;
}
print "The average memory usage for all servers is: ", $totalMem / $count. "%\n";

# Closes the file
close $fh;

3 个答案:

答案 0 :(得分:5)

对于这个用例,哈希比数组要好得多。

#!/usr/bin/perl
use strict;
use feature qw{ say };
use warnings;

use List::Util qw{ min };

my %server;
while (<>) {
    chomp;
    my ($name, $cpu_utilization, $avg_memory, $disk_free)
        = split /:/;
    @{ $server{$name} }{qw{ cpu_utilization avg_memory disk_free }}
        = ($cpu_utilization, $avg_memory, $disk_free);
}

my $least_disk = min(map $server{$_}{disk_free}, keys %server);
say for grep $server{$_}{disk_free} == $least_disk, keys %server;

答案 1 :(得分:4)

choroba's answer 是理想的,但我认为你自己的代码可以改进

  • 除非您需要仅在给定版本的Perl中可用的特定功能,否则不要use v5.26.1。请注意,它还启用use strict,它应该位于您编写的每个Perl程序的顶部

  • die "System cannot find the file specified. $!"错误:open可能失败的原因有多种,除此之外“无法找到”。您的die字符串应包含您尝试打开的文件的路径;失败的原因在于$!

  • 不要使用子程序原型:它们不会按照您的想法执行。 sub header() { ... }应该只是sub header { ... }

  • 声明一个子程序只是稍后调用几行是没有意义的。将header的代码放入行

  • 你显然来自另一种语言。尽可能晚地使用my声明变量。在这种情况下,必须在$count循环之外声明$totalMemwhile

  • perl将在程序退出时关闭所有打开的文件句柄。很少需要明确的close调用,这会让您的代码更加嘈杂

  • $totalMem = $avgMemUsage + $totalMem通常是$totalMem += $avgMemUsage

我希望有帮助

答案 2 :(得分:-1)

关于如何将数据存储在数组中的原始问题......

首先,在文件读取循环外初始化一个空数组:

my @servers = ();

然后,在循环中,在解析完数据后,可以将它们作为子数组存储在数组中(结果数据结构是二维数组):

$servers[$count] = [ $name, $cpuUtil, $avgMemUsage, $diskFree ];

注意,右侧的方括号为服务器的数据块创建子数组,并返回对此新数组的引用。此外,在左侧,我们只使用 $ count 的当前值作为 @servers 数组中的索引,随着值的增加,的大小@servers 数组将自动增长(这称为新元素的自动生成)。或者,您可以新元素推送到循环内的 @servers 数组中,如下所示:

push @servers, [ $name, $cpuUtil, $avgMemUsage, $diskFree ];

这样,您明确要求将新元素添加到数组中,方括号仍然执行相同的子数组创建。

在任何情况下,最终结果是在完成文件读取循环后,您现在有一个2D数组,您可以在其中访问第一个服务器及其无磁盘字段(索引3处的第4个字段)像这样:

my $df = $servers[0][3];

或者检查循环中的所有服务器以找到最小的可用磁盘:

my $min_s = 0;
for ( my $s = 0; $s < @servers; $s++ ) {
    $min_s = $s  if ( $servers[$s][3] < $servers[$min_s][3] );
}
print "Server $min_s has least disk free: $servers[$min_s][3]\n";

与@choroba建议一样,您可以将服务器数据片段/字段存储在哈希中,以便您的代码更具可读性。您仍然可以将您的服务器列表存储在一个数组中,但第二个维度可以是哈希:

$servers[$count] = {
    name          => $name,
    cpu_util      => $cpuUtil,
    avg_mem_usage => $avgMemUsage,
    disk_free     => $diskFree
};

因此,您生成的结构将是一个哈希数组。这里,右边的花括号创建一个新的哈希并返回对它的引用。所以,您可以稍后参考:

my $df = $servers[0]{disk_free};