Linux за българи: Форуми

Програмиране => Web development => Темата е започната от: axelic в Aug 05, 2006, 14:18



Титла: Помощ за perl
Публикувано от: axelic в Aug 05, 2006, 14:18
Здравейте, нужна ми е малко помощ за един скрипт. Налага ми се да направя известна промяна, но тъй като никога не съм работил с Perl ми идва доста нанагорно. Не познавам толкова добре синтаксиса, а и ...алгоритъма нещо ми убягва.
:(

#!/usr/bin/perl

$critical = 27;
$lock = "temp.lock";

$string = `tail -1 tempdaemon.temp`;

($date,$time,$temp) = split(" ",$string);
if ($temp >= "$critical" && !(-f $lock)) {
print "Allert";
system("/usr/bin/touch $lock");
}

if ($temp < "$critical" && -f $_lock) {
`/bin/rm $lock`;


Както се вижда, скрипта дърпа переодично данни от един файл - tempdaemon.temp
в който се записва температурата всяка минута.
Скрипта е за уведомяване ако температурата се покачи над 27 градуса. Проблема е, че ако се качи над въпросните 27 градуса на всяка 1 минута изпраща съобщение, което е прекалено в случей, че температурата се задържи примерно на 27.1 в продължение на часове.
Идеята е така да се модифицира скрипта, че да праща съобщение само ако е над 27 градуса И разликата с предходното изпращане е повече от 0.5 градуса.
Благодаря много предварително. Всякакви идеи са добре дошли.

П.П. Хрумна ми, че евентуално може да има един файл в който да се записва стойността на една вариабла, която започва от "critical" и се променя само ако разликата между нея и "temp" е поне 0.5(в двете посоки), и съответно да има съобщение само при промяна на вариаблата. Така, че в момента въпроса е по скоро кода с който мога да трия/записвам във файл!





Титла: Помощ за perl
Публикувано от: Lord Bad в Aug 05, 2006, 17:16
Това, което ти трябва ще намериш тук. Успех.


Титла: Помощ за perl
Публикувано от: axelic в Aug 07, 2006, 19:46
Цитат (Lord_Bad @ Авг. 05 2006,18:16)
Това, което ти трябва ще намериш тук. Успех.

Много благодаря, но аз се надявах по скоро на директен съвет и може би код. Не ми се налага да използвам Перл, това сега е единичен случей.


Титла: Помощ за perl
Публикувано от: prowler в Aug 10, 2006, 15:37
Примерен код
open(ALERT, $file);
my @line = <ALERT>;

towa ti prochita faila s ime $file i imash pyrwiq red w $line[0]
tam ti e chisloto koeto ti e ot posledniq alert

Примерен код
if(int($line[0] * 10) <= int($temp * 10 - 5)) {
... prawish alert
}

prowerqwa dali prochetenoto chislo e po-golqma s 0.5

Примерен код
open(ALERT, "> $file");
print <ALERT> $temp;
close(ALERT);

towa ti zapiswa wyw faila promenliwata $temp

sglobi teq neshta i si gotow.. :)


Титла: Помощ за perl
Публикувано от: axelic в Aug 24, 2006, 14:42
Здрасти, много благодаря за помоща!!!
Накрая "спастрих" и аз нещо. Работи безпроблемно. Обаче ми се струва малко тромавичко. Ако имаш идея как да стане по-леко, без обаче да се навреди на функционалитета, ще съм благодарско ;)

Примерен код

#!/usr/bin/perl

$file="test.txt";
$critical=27.0;
$string = `tail -1 tempdaemon.temp`;
($date,$time,$temp) = split(" ",$temp_a);
open ( INFILE, "<$file" ) or die "Can't open $file: $!\n";
@lines = <INFILE>;
close INFILE;
$null=0.0;

if ($temp_a>=$critical){
   open ( INFILE, "<$file" ) or die "Can't open $file: $!\n";
        if ($lines[0]!=0.0){
             $temp_t=$lines[0];
             if($temp_a>$temp_t){
                 if(($temp_a-$temp_t)>=0.5){
                      open (OUTFILE, ">$file" ) or die "Can't open $file: $!\n";
                      print OUTFILE "$temp_a\n";
                      print "Send note with temperatur: $temp_a\n";
                      close OUTFILE;
                 }
             }
             if($temp_a<$temp_t){
                 if(($temp_t-$temp_a)>=0.5){
                      open (OUTFILE, ">$file" ) or die "Can't open $file: $!\n";
                      print OUTFILE "$temp_a\n";
                      print "Send note with temperatur: $temp_a\n";
                      close OUTFILE;
                 }
             }
        }
        else{open (OUTFILE, ">$file" ) or die "Can't open $file: $!\n";
                      print OUTFILE "$temp_a\n";
                      print "Send note with temperatur: $temp_a\n";
                      close OUTFILE;
        }
   close INFILE;
}
if ($temp_a<$critical){
     open ( INFILE, "<$file" ) or die "Can't open $file: $!\n";
     if ($lines[0]!=0.0){
     print "Send note with temperatur: $temp_a\n";
     close INFILE;
     open (OUTFILE, ">$file" ) or die "Can't open $file: $!\n";
     print OUTFILE "$null\n";
     close OUTFILE;
     }
}






Титла: Помощ за perl
Публикувано от: VladSun в Aug 24, 2006, 18:58
Не съм чел подробно скрипта, но веднага ми прави впечатление, че отваряш и четеш (а понякога даже не четеш) един и същ файл по няколко пъти.
Имам чувството, че Copy-Paste-a здраво е действал тука :)


Титла: Помощ за perl
Публикувано от: axelic в Aug 24, 2006, 19:44
Цитат (VladSun @ Авг. 24 2006,19:58)
Не съм чел подробно скрипта, но веднага ми прави впечатление, че отваряш и четеш (а понякога даже не четеш) един и същ файл по няколко пъти.
Имам чувството, че Copy-Paste-a здраво е действал тука :)

Ами така е, но съм го направил съвсем целенасочено!
Както вече писах - нямам почти никакво понятие от Perl,
но успях някакси да го направя пустия му скрипт. Изхождам от знания които имам в други насоки, и не претендирам за "отлични постижения". Лесно е да съставиш алгоритъма, но е рудно да го имплементираш, без да имаш почти никакво понятие от особеностите на езика. Точно за това моля за помощ - за "фината настройка".  ;)


Титла: Помощ за perl
Публикувано от: soulcollector в Aug 25, 2006, 04:43
Ами всъщност този файл temp.lock се създава точно с тази цел - след като температурата е станала над 27 градуса, предупреждава и създава файла. Докато файлът съществува и температурата е над 27 няма нови съобщения. Ако температурата спадне и файлът съществува той се трие.
Неудобно в случая е, че всеки път преди да пуснеш daemon-а трябва да си сигурен, че НЕ съществува файл temp.lock

Примерен код

#!/usr/bin/perl

$critical = 27;
$lock = "temp.lock";

$string = `tail -1 tempdaemon.temp`;

($date,$time,$temp) = split / /, $string;

if ($temp >= "$critical" && !(-f $lock)) {
   print "Allert";
   system "/usr/bin/touch $lock";
}

if ($temp < "$critical" && -f $lock) {
   sytem "/bin/rm $lock";
}


Друг вариант е да не използваш такъв файл, а да четеш последните два реда от tempdaemon.temp и да вземеш двете температури. После сравняваш - Ако текущата е над или е 27, а предишната под 27 - ALERT. Т.е

Примерен код

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

my $critical = 27;

# четене на температурите - предполага се, че DATE TIME TEMP са разделени с
# един интервал и всеки ред в tempdaemon.temp e в този вид
my ($temp_b, $temp_n) = split /\n/, `tail -2 tempdaemon.temp | cut -d ' ' -f 3`;

if ($temp_n >= $critical && $temp_b < $critical) {
   print "ALERT\n"
}



PS. За да не стават такива грешки, като тази с $_lock вместо $lock във втория if твоят код е добре да се ползват use warnings; и use strict;


Титла: Помощ за perl
Публикувано от: axelic в Aug 25, 2006, 13:13
Цитат (soulcollector @ Авг. 25 2006,05:43)

Здрасти, погледни моля те втория ми пост в тази тема - там кода е съвсем друг, а и вече функционира.


Титла: Помощ за perl
Публикувано от: VladSun в Aug 25, 2006, 18:31
Примерен код

#!/usr/bin/perl

$file = "test.txt";
$critical = 27.0;
$string=`tail -1 tempdaemon.temp`;
($date, $time, $temp_a) = split(" ", $string);

$last_temp = `cat $file`;
chomp($last_temp);

if ( ($temp_a >= $critical) and ($last_temp < $critical) )
{
    `echo $temp_a > $file`;
    print "Send note with temperatur: $temp_a\n";
}
else
{
    `echo $temp_a > $file`;
}



Това ми се струва, че отговаря на задачката макар, че вече стана по-лесно да го напишеш на bash script :) .
Само не разбрах  - къде се използва temp.lock в твоя скрипт ( във втория пост ) и какво разбираш под предупреждение - само print "Bla bla" стига ли? :)





Титла: Помощ за perl
Публикувано от: soulcollector в Aug 26, 2006, 00:24
Точно този скрипт силно се съмнявам да работи. А ако наистина работи, бих искал да знам откъде се взима стойността на $temp_a още на ред 6?

Ето до какво го докарах

Примерен код

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

sub temp_warn ($$);

my $file = "test.txt";
my $critical = 27.0;

my $string = `tail -1 tempdaemon.temp`;

my ($date, $time, $temp) = split / /, $string;

open INFILE, "$file" or die "Can't open $file: $!\n";
my $temp_t = <INFILE>;
close INFILE;
chomp $temp_t;

if ($temp >= $critical and ($temp_t == 0.0 or abs ($temp - $temp_t) >= 0.5)) {
   temp_warn $file, $temp;
   print "Send note with temperature: $temp\n";
}

if ($temp < $critical and $temp != 0.0) {
   temp_warn $file, '0.0';
   print "Send note with temperature: $temp\n";
}

sub temp_warn ($$) {
   my $file = shift;
   my $temp = shift;

   open OUTFILE, "> $file" or die "Can't open file $file: $!\n";
   print OUTFILE "$temp\n";
   close OUTFILE;
}


Би могло да се сложи един return в края на блока на първият if с цел да се избегне излишната (в случая) проверка на втория if.





Титла: Помощ за perl
Публикувано от: VladSun в Aug 26, 2006, 15:38
Прав си - просто модифицирах дадения вече скрипт и не съм гледал нагоре как се дава стойност на променливите.

Но ... кому е нужно толкова сложно да е всичко - няма нужда от Perl при условие, че половината от кода е bash команди?

Примерен код

#!/bin/bash

file="file.txt"
critical_temp=27
temp=$(tail -1 tempdaemon.temp | cut -s -d" " -f3)
last_temp = $(cat $file);

echo $temp > $file;

if [ "$temp" -gt "$critical_temp" ] && [ "$last_temp" -lt "$critical_temp" ];
then
   echo "Send note with temperature: $temp";
fi


Титла: Помощ за perl
Публикувано от: axelic в Aug 26, 2006, 16:39
Може би аз не съм се изразил ясно.
Всяка минута в tempdaemon.temp се записва актуалната температура - дата, час, температура(temp_a). Скрипта чете от него, и ако мине над 27 градуса,започва да изпраща съобщения с актуалната температура. Проблема е, че това означава всяка минута да се изпраща съобщение(а температурата не мърда много - с 0.1 градус на 30 минути), което е много досадно, а и скъпо - съобщенията са с SMS(т.е. между 27.0 и 27.2 обикновено минава 1 час, а се получават 60 SMS). Затова се взе решение да се праща съобщение на всеки 0.5 градуса, след като е минала критичната температура. т.е. ако предположим, че "входната" температура е 27.1, то първия SMS да е при нея (входната), а втория - или при 27.6, или ако падне под 27.0 градуса. Знам, че скрипта ми изобщо не е елегантен, но досега изобщо не бях правил каквото и да е на Perl.

Обяснението на моя вариант на скрипта е следното:
Всяка минута в tempdaemon.temp се записва новата актуална температура. Скрипта чете от него, и ако температурата скочи над 27 градуса:
1. проверява, дали във файла test.txt на първия ред стойността е 0.0, и ако е - праща съобщение, и записва актуалната температура на мястото на 0.0(примерно 27.1).
2. при следващата(след една минута) температура взета от tempdaemon.temp се проверява, дали е над 27 градуса, дали в test.txt стойността е различна от 0.0(а тя е, и в такъв случей дали е по-голяма от нея с поне 0.5 градуса. Ако да - праща съобщение, и записва новата на мястото на старата в test.txt. Ако не е по-голяма с поне 0.5 градуса, и стойността е различна от 0.0 - просто продължава нататък изпълнението на кода и не записва/праща нищо.
В моя пример - при записани последно 27.1 градуса в test.txt, да кажем, че температурата се покачва бавно, ще се изпрати съобщение едва когато разликата между актуалната и тази в test.txt стане равна или по-голяма от 0.5 градуса - сефте при минимум 27.6 ;) . Има ли пик - примерно била е 27.1 а след една минута се докладва, че е 28.5 - то това(28.5) ще стане актуалната записана в test.txt температура, и разбира се ще се изпрати съобщение.
Пада ли - по същия начин. Особеното е, че ако температурата падне под 27.0 градуса, то първо ще провери дали в test.txt стойността е 0.0, и ако не е (това означава, че преди една минута температурата е била над 27.0 градуса) ще изпрати съобщение със актуалната температура (примерно 26.9 - да спре да се шашка админа ;) ), и веднага след това ще запище в test.txt стойността 0.0.





Титла: Помощ за perl
Публикувано от: VladSun в Aug 26, 2006, 16:59
Примерен код

#!/bin/bash

file="file.txt"
critical_temp=27
treshold=0.5
temp=$(tail -1 tempdaemon.temp | cut -s -d" " -f3)
last_temp = $(cat $file);


if [ "$temp" -gt "$critical_temp" ];
then
   if [ "$last_temp" -lt "$critical_temp" ];
   then
      echo $temp > $file;
      echo "Send note with temperature: $temp";
   else
      delta=$(($temp - $last_temp))
      if [ "$delta" -gt "$treshold" ];
      then
        echo $temp > $file;
        echo "Send note with temperature: $temp";
      fi
   fi
else
   if [ "$last_temp" -gt "$critical_temp" ];
   then
      echo $temp > $file;
      echo "Send note with temperature: $temp";
   else
fi


Титла: Помощ за perl
Публикувано от: soulcollector в Aug 26, 2006, 23:19
Това би трябвало да правиш каквото искаш.
Примерен код

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

sub temp_warn ($$);

my $file = "test.txt";
my $critical = 27.0;

my $temp = `tail -1 tempdaemon.temp | cut -s -d ' ' -f 3`;

open INFILE, "$file" or die "Can't open $file: $!\n";
my $temp_t = <INFILE>;
close INFILE;
chomp $temp_t;

if ($temp >= $critical and ($temp_t == 0.0 or $temp - $temp_t >= 0.5)) {
        temp_warn $file, $temp;
        print "Send note with temperature: $temp\n";
}
if ($temp < $critical and $temp != 0.0) {
        temp_warn $file, '0.0';
        print "Send note with temperature: $temp\n";
}

sub temp_warn ($$) {
        my $file = shift;
        my $temp = shift;

        open OUTFILE, "> $file" or die "Can't open file $file: $!\n";
        print OUTFILE "$temp\n";
        close OUTFILE;
}



Но VladSun може и да е прав, че bash е по - добър избор, а и последният му скрипт ми изглежда еквивалентен.

Към VladSun: за инициализациите имах предвид точно скрипта, който си копирал.





Титла: Помощ за perl
Публикувано от: axelic в Aug 27, 2006, 13:59
VladSun, благодаря ти, но скрипта изрично трябва да бъде на Perl(не е нещо зависещо от мен).

soulcollector, благодаря ти и на теб, но какво ще стане, ако в някакъв момент температурата е била 27.7, в следващия е 27.2?
Примерен код

if ($temp >= $critical and ($temp_t == 0.0 or $temp - $temp_t >= 0.5)) {
       temp_warn $file, $temp;
       print "Send note with temperature: $temp\n";

Както аз го виждам - ще е по-голяма от критичната(ще е 27.2),  $temp_t == 0.0 няма да е вярно, а 27.2-27.7 ще е по-малко от 0.5 ;). т.е. температурата ще е паднала с 0.5 градуса, но това няма да доведе до съобщение.


Титла: Помощ за perl
Публикувано от: VladSun в Aug 27, 2006, 18:07
axelic - имаш структурата, работи - прехвърли я на Perl.
Само не разбирам, при условие, че ползваш bash команди в скрипта как изпълняваш изискването :) - то би имало смисъл единствено, ако правиш нещо, което да работи и под Линукс и под Уиндоус.
И още нещо - това с използването на 0.0 като маркер е абсолютно безсмислено, при условие, че имаш във всеки един момент текущата темпераура и последната такава.





Титла: Помощ за perl
Публикувано от: soulcollector в Sep 05, 2006, 02:25
Аз  в предния си пост бях сложил
Примерен код

abs ($temp - $temp_t) >= 0.5

 но от обяснението ти какво точно трябва да прави разбрах (явно погрешно), че при падане на температурата съобщение се праща само когато падне под критичната.