2012-07-26 15 views
5

मैं एक पर्ल स्क्रिप्ट पर काम कर रहा हूं जो हमारे नेटवर्क पर मशीनों की स्कैनिंग के स्वचालन में मदद करने के लिए है। मैं व्यापार द्वारा प्रोग्रामर नहीं हूं, लेकिन इस परियोजना को मुझे कम से कम कोई भी सौंपा गया है, और मैं काफी स्टंप हूं। मुझे बताए जाने की प्रकृति की व्याख्या करने से पहले, मुझे जो कुछ भी कर रहा है उसकी रूपरेखा बताएं।पर्ल एक सशर्त के भीतर मूल्य बदल रहा है?

असल में, यह स्क्रिप्ट हर घंटे घंटों में चली जाएगी। चलाए जाने पर, यह एक ऐसी फाइल की जांच करेगा जिसमें सक्रिय आईपी का लॉग हो और उन्हें केवल डीएचसीपी लॉग के खिलाफ जांचें जो स्थिर हैं। इसके बाद इन्हें एक हैश में रखा जाता है (एक नया अगर प्रारंभ करने के लिए ध्वजांकित किया जाता है, अन्यथा स्टेकिंग का उपयोग करके लोड किया जाता है), आईपी होने की कुंजी और एक सरणी के भीतर उनके मैक [0] और "आखिरी स्कैन की गई" तिथि [1] शुरू में सेट होती है 1 9 700101. स्क्रिप्ट का अगला भाग आज की तारीख और "आखिरी स्कैन" तिथि के बीच की तारीख की तुलना करता है - और यदि यह एक निश्चित सीमा के तहत है, तो यह हमारे स्कैनर को एक प्रश्न भेजता है।

जो मुद्दा मुझे इतना खो गया है वह यह है कि जब तिथि की जांच की जा रही है, तो मुझे लगता है कि तिथि मान (अद्यतन "अंतिम स्कैन") सशर्त में प्रवेश करने से पहले सेट किया जा रहा है। हालांकि यह मेरे लिए प्रतीत नहीं होता है, यह एकमात्र संभावना है जिसे मैं सोच सकता हूं।

कोड कि हैश

if(init == 1){ 
      %SCAN =(); 

      @data =(); 

      foreach $key (keys %IPS){ 

        $unsavedDB = 1; 

        $data[0] = $IPS{$key}; 
        $data[1] = 19700101; 

        print $data[1]; 

        $SCAN{$key} = \@data; 
      } 
}else{ 
      #repeat of the above code, but with a if(exists...) to prevent duplicates from being added to the hash that is loaded via storables. 
} 

कोड उस तारीख की जाँच करता है (जो पहले से सेट किया गया है, और आज के लिए 20,120,726 होगा) के लिए आईपी/MACs कहते हैं: यहाँ कोड के प्रासंगिक हिस्सा है। बीच उपरोक्त कोड और वहाँ पीछा कर रहा है कुछ भी नहीं है लेकिन टिप्पणी

$scanned = 0; 

    foreach $key (keys %SCAN){ 

      $lastScanned = $SCAN{$key}[1]; 

      if(($date - $lastScanned) > $threshold){ 
        $unsavedDB = 1; 

        $toScan = ${$key}[0]; 

        #omitted data for security reasons, just basically forms a string to send to a scanner 

        $SCAN{$key}[1] = $date; 

        $scanned++; 
      } 
    } 

    print "finished. $scanned hosts queued\n"; 

अब, कारण मुझे विश्वास है कि यह है कि मूल्य बदला जा रहा है इससे पहले कि पाश में प्रवेश है जब मैं पहले सही एक 'प्रिंट $ lastScanned' बयान जोड़ने 'अगर (($ तारीख ...) {' तिथि जो पहले भी $ तारीख को सौंपी गई थी, मुद्रित की गई थी - लेकिन अगर मैं '$ SCAN {$ key} [1] = $ date;' कथन, प्रिंट पर टिप्पणी करता हूं बयान '1 9 700101' तिथि और सबकुछ कार्य करेगा जैसा कि यह होना चाहिए। क्या हो रहा है? $ SCAN {$ key} [1] ऊपर दिखाए गए दो स्थानों को छोड़कर कभी छुआ नहीं जा रहा है।

क्षमा करें अगर यह बहुत बुरी तरह से है phrased, या समझ में नहीं आता है। मैंने कुछ ऐसा समझाया जो सेंट है मुझे घंटों के लिए कूद रहा है।

धन्यवाद!

उत्तर

8

क्योंकि आपके @data सरणी वैश्विक है, हर बार अपने को अंजाम बयान

$SCAN{$key} = \@data; 

आप $SCAN{$key} को ही@data सरणी के लिए एक संदर्भ बताए जा रहे हैं। इस प्रकार, %SCAN में सभी मान एक ही सरणी को इंगित करते हैं, जो संभवतः आप जो चाहते हैं वह नहीं है।

ऐसे कई तरीके हैं जिनमें आप इसे ठीक कर सकते हैं।शायद सबसे सरल आप एक शाब्दिक सरणी का उपयोग करने के लिए पूरे पाश पुनर्लेखन सकता कोड,

$SCAN{$key} = [ @data ]; 

को वैकल्पिक रूप से $SCAN{$key} को @data सरणी के एक प्रतिलिपि के लिए एक संदर्भ आवंटित ऊपर लाइन बदलकर बनाने के लिए हो सकता है, पाश — कि जिस तरह से आप प्रत्येक यात्रा पर एक नया अलग सारिणी निर्मित अंदर my साथ की घोषणा की:

foreach $key (keys %IPS) { 
     $unsavedDB = 1; 

     my @data; # <--- this line is new! 

     $data[0] = $IPS{$key}; 
     $data[1] = 19700101; 

     print $data[1]; 

     $SCAN{$key} = \@data; 
} 

हालांकि, क्या तुम सच में करना चाहिए, के बजाय सिर्फ च इस विशेष बग के लक्षणों को ixing, how variable scoping works in Perl सीखें और इसका उपयोग कैसे किया जाना चाहिए, और तदनुसार अपना कोड दोबारा लिखें।

विशेष रूप से, अपने कोड को देखते हुए, मुझे बहुत संदेह है कि आप अपने कोड में the strict pragma का उपयोग नहीं कर रहे हैं। आप साफ पर्ल कोड लिखने के लिए चाहते हैं, पहले बात तुम सच में क्या करना चाहिए पहले जोड़ें है अपने सभी लिपियों के लिए दो पंक्तियाँ, तुरंत #! पंक्ति के बाद निम्नलिखित:

use strict; 
use warnings; 

strict pragma बलों आप कुछ से बचने के लिए खराब और त्रुटि-प्रवण आदतों, जैसे कि प्रतीकात्मक संदर्भ या अविकसित वैश्विक चर का उपयोग करना, जबकि the warnings pragma दुभाषिया आपको कई अन्य मूर्ख, जोखिम भरा, संदिग्ध या अन्यथा अवांछित चीजों के बारे में चेतावनी देता है (जिसे आपको वास्तव में त्रुटियों के रूप में व्यवहार करना चाहिए और जब तक आपको कोई नहीं मिलता अधिक चेतावनियां)।

बेशक

, इसका मतलब यह नहीं है कि आप बस के साथ my (या our) बस strict खुश करने के लिए स्क्रिप्ट की शुरुआत में अपने सभी चर घोषित करना चाहिए। इसके बजाय, आपको प्रत्येक चर को देखना चाहिए, देखें कि यह वास्तव में कहां उपयोग किया जाता है, और इसे उस आंतरिक क्षेत्र में घोषित करें जिसमें इसकी आवश्यकता है। (यदि आप कोड के विभिन्न हिस्सों में समान वैरिएबल नाम का पुन: उपयोग कर रहे हैं, तो उनको अलग से व्यवहार करें चर और उनमें से प्रत्येक को अलग से घोषणा करते हैं।) याद रखें कि आप

foreach my $key (keys %IPS) { 

या

while (my $line = <>) { 

पी.एस. में पाश बयान में पाश चर घोषणा कर सकते हैं के रूप में,। मैं भी कोड में एक चिंताजनक टिप्पणी देखा आप हमें पता चला:

# repeat of the above code, but with ... 

आम तौर पर, कोड दोहराव उस तरह का एक बड़ा चमकती संकेत है कि आप शायद कुछ गलत कर रहे हैं — प्रोग्रामिंग के स्वर्ण नियम "Don't repeat yourself. है होना चाहिए "

बेशक

, वहाँ उन कुछ, बहुत बहुत दुर्लभ अवसरों जहां दो अलग अलग तरीकों अनिवार्य रूप से एक ही बात करने के लिए जरूरत करना , लेकिन इतने सारे छोटे और मनमाने ढंग से अंतर के साथ है कि यह करने के लिए क्लीनर है भर peppered हैं पूरी बात दो बार लिखें। लेकिन मैं बहुत हैरान है कि अगर यहां मामला — था मुझे यकीन है आप केवल एक बार है कि कोड लिख सकते हैं, और बस हो सकता है एक उपयुक्त स्थान पर एक

if (not $init and exists ...) { 

जांच सम्मिलित होगी।

+0

धन्यवाद! यह बहुत उपयोगी था! मैं आपके द्वारा लिंक की गई सभी चीज़ों के माध्यम से पढ़ा जाएगा और कोड के उस चिंताजनक अनुभाग को संशोधित करूँगा! –

3

Ilmari कहते हैं, आपकी समस्या यह है कि एक ही दो-तत्व वाली सरणी है कि पहले कोड ब्लॉक में @data था, को %SCAN अंक के प्रत्येक तत्व तो $SCAN{<anything>}[1] सभी IP पतों के लिए एक ही चर रहा है है।

इसे ठीक करने के मेरी प्राथमिकता @data के बारे में भूल जाते हैं और

$SCAN{$key} = [ $IPS{$key}, '19700101' ]; 

जो एक नई अज्ञात सरणी हर बार बयान निष्पादित किया जाता है उत्पन्न करता है और हैश के मूल्य के रूप में यह करने के लिए एक संदर्भ प्रदान करती है लिखने के लिए होगा।

ध्यान दें कि मैंने तिथि के लिए एक स्ट्रिंग का उपयोग किया है, क्योंकि आप $date - $lastScanned जैसी चीजें लिख सकते हैं: दिनांक अंकगणित उससे अधिक जटिल है। 1-FEB-2012 से 31-JAN-2012 घटाकर 20120201 - 20120131 या 70 हो जाएगा!

सौभाग्य से यह आसान बनाने के लिए मॉड्यूल हैं और आप मॉड्यूल Time::Piece का उपयोग कर सकते हैं, जो मूल मॉड्यूल है (यानी यह पर्ल v5.9 के बाद मानक पर्ल के साथ स्थापित हो जाता है) और आपको इस तरह के अंकगणित करने देता है।

अपने कार्यक्रम के शीर्ष पर, use strict और use warnings के बाद, आपके द्वारा लिखी

use Time::Piece; 

और फिर बाद में, अपने प्रारंभिक समय के लिए, लिखने

my $initial = localtime(0); 

और फिर

my $date = localtime; 

आप उन तारीखों को देख सकते हैं जो दो मानों को प्रिंट करके प्रिंट करते हैं उन्हें

print $initial, "\n"; 
print $date, "\n"; 

तरह

Thu Jan 1 00:00:00 1970 
Fri Jul 27 01:40:53 2012 

और एक सरल घटाव आप वास्तविक अंतर देता है कुछ, सेकंड

print $date - $initial; 

तो अगर $threshold दिनों में है आप अंतराल की जांच कर सकते में दिखाई देंगे जो

if ($date - $lastScanned > $threshold * 24 * 60 * 60) { ... } 
लिखकर

मुझे आशा है कि मैंने आपको यहां डराया नहीं है, लेकिन इसे बदलने की जरूरत है और मैंने सोचा कि आपको पता होना चाहिए। मॉड्यूल इस से बहुत कुछ करेगा, और यदि आप प्रलेखन को देखना चाहते हैं तो यह here है। और अगर आप अटक जाते हैं तो कृपया एक और सवाल पूछें।

संबंधित मुद्दे