Чтение данных из файла в массив для манипуляции в скрипте Perl - PullRequest
0 голосов
/ 27 мая 2018

Новое в Perl.Мне нужно выяснить, как читать из файла, разделенного (:), в массив.Затем я могу манипулировать данными.

Вот пример файла 'serverFile.txt' (просто сгенерировал случайные #). Поля: Имя: Загрузка ЦП: 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 голосов
/ 27 мая 2018

ответ Чоробы идеально идеально, но я думаю, что ваш собственный код можно улучшить

  • Не 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

Надеюсь, это поможет

0 голосов
/ 05 июня 2018

К вашему первоначальному вопросу о том, как сохранить данные в массиве ...

Сначала инициализируйте пустой массив вне цикла чтения файла:

my @servers = ();

Затем, внутриПосле того, как вы проанализировали части данных, вы можете сохранить их в своем массиве как подмассивы (результирующая структура данных - двумерный массив):

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

Обратите внимание, квадратные скобки наПраво создать вложенный массив для частей данных сервера и вернуть ссылку на этот новый массив.Кроме того, в левой части мы просто используем текущее значение $ count в качестве индекса в массиве @ servers и по мере увеличения значения размер серверов @ массив будет расти автоматически (это называется автовивификацией новых элементов).В качестве альтернативы, вы можете вставить новые элементы в массив @ servers внутри цикла, например:

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

Таким образом, вы явно запросите новый элементдобавляемый в массив и квадратные скобки по-прежнему делают то же самое создание подмассива.

В любом случае конечный результат состоит в том, что после того, как вы закончили с циклом чтения файла, у вас теперь есть2D-массив, в котором вы можете получить доступ к первому серверу и его свободному полю диска (4-е поле в индексе 3) следующим образом:

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};
0 голосов
/ 27 мая 2018

Для этого случая использования хеш намного лучше, чем массив.

#!/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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...