【问题标题】:Reading data from file into an array to manipulate within Perl script将文件中的数据读入数组以在 Perl 脚本中进行操作
【发布时间】:2018-11-06 09:42:15
【问题描述】:

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;

【问题讨论】:

  • 我建议您将($name, $cpuUtil, $avgMemUsage, $diskFree) 定义为my inside 循环。这将防止您意外使用这些变量,并在代码中为您节省一个额外的定义行。这也是更合乎逻辑的方式。

标签: arrays perl file


【解决方案1】:

对于这个用例,散列比数组好得多。

#!/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;

【讨论】:

    【解决方案2】:

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

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

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

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

    • 声明一个子例程只是在几行之后调用它是没有意义的。将header 的代码放入行中

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

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

    • $totalMem = $avgMemUsage + $totalMem 通常写成$totalMem += $avgMemUsage

    希望对你有帮助

    【讨论】:

    • @choroba 你说得对,我来自 cpp,我也是初学者。非常好的提示,谢谢您
    【解决方案3】:

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

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

    my @servers = ();
    

    然后,在循环中,解析出数据片段后,可以将它们作为子数组存储在数组中(生成的数据结构是二维数组):

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

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

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

    这样,您明确要求将新元素添加到数组中,而方括号仍然会创建子数组。

    无论如何,最终结果是在完成文件读取循环后,您现在拥有一个二维数组,您可以在其中访问第一个服务器及其磁盘空闲字段(索引 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};
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-25
      • 2013-04-01
      • 2019-03-08
      • 2015-05-12
      • 2014-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多