URL: https://www.opennet.ru/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 9451
[ Назад ]

Исходное сообщение
"Странное поведение цикла при считываии хэша"

Отправлено lv2 , 08-Май-12 09:15 
Здравствуйте,

Пытаюсь реализовать своими рукуми первый раз в жизни перл скрипт по заданию начальника.
Занятие при  отсутствии знаний оказалось непростым.
Изначально задание следующее:
Необходимо отследить в логах апача определенные IP аддреса. Есть список этих адресов.
Я вчера написал bash скрипт, но он за ночь прошел очень мало, поэтому начальник сказал писать на перле используя Хэш.

В хэш я решил занести эти IP адреса из файла в поля ключей. И присвоить им значения 0.
По мере парсинга и нахождения значение должно прибавляться к тому ключю который нашло в логе.
Для эксперимента взял 7 адресов, создал файл адресов с ними и создал второй файл(анализируемый). В него продублировал те же самые адреса 2 раза

Написал кой какой скрипт (после 5ти часов в инете), расставил по нему принтов чтоб понимать как он работает и работает ли вобще. И результат анализа стал выводить в аутпут файл.

На определенной  стадии заметил странное поведение. В Выводу принтов в консоль было 8 входов во внешний цикл (где подставляется искомый адрес) и 15 входов во второй цикл (где перебираются строки анализируемого файла). По логике должно быть 7 и 14. Иду в файлы, замечаю снизу пустую строку. Убираю в файле имитирующем логфайл апача - все ок. Убираю в файле IP адресов - вхождений во внутренний цикл становится только 2 вместо 14 или дажк 15 как было. Возвращаю пустую строку  - снова 15.

Не могли бы вы посянить что именно происходит и почему скрипт так себя ведет?


Вот в таком порядке идут IP адреса  в файле /tmp/1ip
1.197.174.131
1.197.174.247
24.187.239.58
27.189.35.33
41.34.142.120
41.35.176.113
41.35.180.236


А вот в таком они почему то заносятся в хэш
1.197.174.247    0
41.35.176.113    0
41.34.142.120    0
1.197.174.131    0
24.187.239.58    0
41.35.180.236    0
27.189.35.33    0


вот сам скрипт

#!/usr/bin/perl -w

use warnings;
$to="/tmp/result";
$weblog="/tmp/2log";
####Populate hash
my %hash = do {
    open my $f, '</tmp/1ip' or die $!;
    map {chomp; $_ => 0} <$f>;
};


#Opens logfile
open(FH,"$weblog")or die"Can not open $weblog: $!\n";

#Defines output file
open(NEW,">>$to");


while (($key, $value) = each(%hash)){

$a=$key;
$b=$value;

while(<FH>){

     next if (!/$a/);

print " $_ internal cycle \n";
if(/$a/){print NEW "$_";$b++}
next;
}
print "$a external\n";
print NEW "\n $a: $b: $weblog\n";
next;
}

Вот вывод в консоль до убирания пустой строки

1.197.174.131
internal cycle
1.197.174.247
internal cycle
24.187.239.58
internal cycle
27.189.35.33
internal cycle
41.34.142.120
internal cycle
41.35.176.113
internal cycle
41.35.180.236
internal cycle
1.197.174.131
internal cycle
1.197.174.247
internal cycle
24.187.239.58
internal cycle
27.189.35.33
internal cycle
41.34.142.120
internal cycle
41.35.176.113
internal cycle
41.35.180.236
internal cycle

internal cycle
external
41.35.176.113 external
41.34.142.120 external
24.187.239.58 external
41.35.180.236 external
27.189.35.33 external
1.197.174.247 external
1.197.174.131 external


И после

1.197.174.247
internal cycle
1.197.174.247
internal cycle
1.197.174.247 external
41.35.176.113 external
41.34.142.120 external
1.197.174.131 external
24.187.239.58 external
41.35.180.236 external
27.189.35.33 external

Заранее спасибо за помощь.


Содержание

Сообщения в этом обсуждении
"Странное поведение цикла при считываии хэша"
Отправлено ACCA , 09-Май-12 07:27 
> Не могли бы вы посянить что именно происходит и почему скрипт так
> себя ведет?

Потому, что ты поискал первый ключ до конца файла, а потом искать стало негде.

Кроме того, неясно откуда у тебя файл. Если хоть каким-то боком приложена винда - ожидай в конце строки CRLF, с которыми chomp не справляется.

> А вот в таком они почему то заносятся в хэш
> 1.197.174.247 0

У хэша нет порядка, он изображает неупорядоченное множество. Более того, в Perl приняты специальные меры, чтобы порядок ключей оказывался случайным при каждом запуске. Поэтому сервера на PHP, Java и всяких .NET можно легко свалить длинным запросом, а Perl - нет.


> вот сам скрипт

В первый раз вижу JavaScript программу, писаную Perl'ом. :)

> #!/usr/bin/perl -w
> use warnings;

Это тавтология. Следовало бы


#!/usr/bin/perl
use warnings;
use strict;

Забудешь кого-нибудь из этой пары - есть шанс прокатиться в дурку.


> my %hash = do {
>     open my $f, '</tmp/1ip' or die $!;
>     map {chomp; $_ => 0} <$f>;
> };

1. значение 0 - плохая идея, хуже него только undef. Сделай 1
2. если адресов немного - зачем файл? Сделай статический список


> while (($key, $value) = each(%hash)){

Не пользуйся each - это реликт Perl 4, с побочными эффектами.

Не открывай файлы без крайней нужды, пользуйся <>, где возможно.



#!/usr/bin/perl
use warnings;
use strict;

use io IN => ':crlf';    # для DOS
binmode STDIN, ':crlf';

my %hash = (
   '1.197.174.131'  => 1,
   '1.197.174.132'  => 1,
   '1.197.174.133'  => 1,
   '1.197.174.134'  => 1,
.....
);
my %count;

while (<>) {
   while (/\b(\d+\.\d+\.\d+\.\d+)\b/go) {
       $count{$1}++ if $hash{$1}; # домашнее задание - победи autovivification
   }
}

foreach my $k (sort keys %count) {
   print "$k: $count{$k}\n";
}