2010-07-07 14 views
7

में एक सिस्टम() कमांड चलाने के दौरान प्रगति दिखा रहा है मेरे पास एक पर्ल स्क्रिप्ट है जो कुछ कार्य करता है, जिनमें से एक system कमांड "tar -cvf file.tar....." पर कॉल करना है।पर्ल

इसमें अक्सर कुछ समय लग सकता है, इसलिए मैं कॉल प्रगति पर है, जबकि # स्क्रीन पर प्रतिबिंबित करने के लिए कमांड लाइन को प्रगति संकेतक को दोबारा गूंजना चाहूंगा।

मैं कुछ खोद रहा हूं और fork भर में ठोकर खा रहा हूं। क्या यह जाने का सबसे अच्छा तरीका है? क्या system कमांड को फोर्क करना संभव है, फिर थोड़ी देर लूप बनाएं जो $pid के फोर्क द्वारा लौटाए गए स्टॉज़ पर जांच करता है?

मैंने waitpid के संदर्भ भी देखे हैं .... मुझे लगता है कि मुझे इसका उपयोग करने की आवश्यकता है।

fork system("tar ... ") 
while (forked process is still active) { 
    print # 
    sleep 1 
} 

क्या मैं गलत पेड़ को भड़क रहा हूं?

बहुत धन्यवाद जॉन

+0

'फोर्क' का वापसी मूल्य बच्चे की प्रक्रिया आईडी है, अगर यह माता-पिता है, या 0 अगर यह बच्चा है, या अगर कांटा विफल हो जाता है तो अनिश्चित। Perldoc -f कांटा देखें। –

उत्तर

1

मैं इस

open my $tar, "tar -cvf file.tar..... 2>&/dev/null |" 
    or die "can't fork: $!"; 
my $i = 0; 
while (<$tar>) { 
    if(i++ % 1000 == 0) print; 
} 
close $tar or die "tar error: $! $?"; 
+2

कृपया अपनी फ़ाइल/प्रक्रिया हैंडल के लिए स्थानीय शब्दावली का उपयोग करें, ग्लोबल्स नहीं। – Ether

+0

मेरा पर्ल थोड़ा जंगली है, मुझे नहीं पता था कि यह फ़ाइल हैंडल के लिए संभव है। धन्यवाद, मैं अगली बार कोशिश करूंगा। –

7

पर्ल की तरह कुछ की कोशिश करेंगे इस के लिए एक अच्छा निर्माण, कहा जाता है "पाइप खुल जाता है।" आप शेल प्रॉम्प्ट पर perldoc -f open टाइप करके इसके बारे में अधिक पढ़ सकते हैं।

open(my $tar, '-|', 'tar', ...) or die "Could not run tar ... - $!"; 
    while (<$tar>) { 
     print "."; 
    } 
    print "\n"; 
    close($tar); 

कुछ है कि एक हैश निशान हर 10 से 100 लाइनों या तो प्रिंट एक अच्छा gaugebar पाने के लिए के साथ print "." बदलें:

# Note the use of a list for passing the command. This avoids 
# having to worry about shell quoting and related errors. 
open(my $tar, '-|', 'tar', 'zxvf', 'test.tar.gz', '-C', 'wherever') or die ...; 

यहाँ एक उदाहरण दिखा एक टुकड़ा है।

+0

हाय जोहान ... यह वही है जो मैं बाद में हूं! आपके उत्तर और उदाहरण के लिए बहुत धन्यवाद। उदाहरण कोड देखते समय मुझे हमेशा इतना आसान लगता है। जॉन – john

+0

एक प्रश्न .... प्रिंट लाइन पर कॉमा क्यों? वह क्या करता है – john

+0

कॉमा की आवश्यकता नहीं है, मैंने इसे उदाहरण से हटा दिया ;-) – Johan

6

एक उदाहरण है कि बच्चे प्रक्रिया उत्पादन के किसी भी प्रकार लेखन पर निर्भर नहीं करता है, और बस के रूप में लंबे समय के रूप में यह चल रहा है एक दूसरे एक बार के बारे में डॉट प्रिंट:

use POSIX qw(:sys_wait_h); 
$|++; 

defined(my $pid = fork) or die "Couldn't fork: $!"; 

if (!$pid) { # Child 
    exec('long_running_command', @args) 
    or die "Couldn't exec: $!"; 
} else { # Parent 
    while (! waitpid($pid, WNOHANG)) { 
    print "."; 
    sleep 1; 
    } 
    print "\n"; 
} 

हालांकि यह शायद करने के लिए खड़े हो सकता है अधिक त्रुटि-जांच, और वहां वास्तव में सीपीएएन पर कुछ बेहतर हो सकता है। Proc::Background इस तरह की नौकरी को दूर करने के लिए वादा करता है लेकिन मुझे यकीन नहीं है कि यह कितना विश्वसनीय है।

+0

हाय और इस पर आपकी सहायता के लिए धन्यवाद। मैं इसे भी आज़मा दूंगा और देख सकता हूं कि कौन सी विधि सबसे अच्छी सूट है। मुझे आपकी $ | ++ टिप पसंद है। मैं एक चयन (STDOUT) और फिर $ | = 1 कर रहा हूं – john

1

लंबे समय तक चलने वाले कार्य के दौरान प्रगति दिखाने के लिए, आपको Term::ProgressBar उपयोगी मिलेगा - यह आपके द्वारा वर्णित "स्क्रीन पर # प्रिंटिंग" कार्यक्षमता है।

2
$|++;  
open(my $tar, 'tar ... |') or die "Could not run tar ... - $!"; 
     while ($file=<$tar>) { 
      print "$file"; 
     } 
     print "\n"; 
     close($tar); 

यह टैर से प्राप्त फ़ाइल नाम प्रिंट करता है।

0

यदि आप बच्चे की प्रक्रिया से डेटा को मूल प्रक्रिया में वापस प्राप्त करना चाहते हैं, तो आपको बाहरी कंडिशन की आवश्यकता होने पर हॉब्स प्रदान किया जाता है। मैं tempfs का उपयोग कर समाप्त हुआ क्योंकि यह एक फ़ाइल की तरह सरल था, लेकिन डिस्क पर आईओ हिट नहीं डालता है।

** महत्वपूर्ण ** आपको बच्चे की प्रक्रिया से बाहर निकलने की आवश्यकता है, अन्यथा "बच्चे" प्रक्रिया एक ही स्क्रिप्ट के साथ जारी रहेगी और आपको डबल print कथन मिलेगा। तो नीचे दिए गए उदाहरण में foreach (@stdoutput) केवल एक बार स्क्रिप्ट में होने के बावजूद दो बार होगा।

$shm_id = time; #get unique name for file - example "1452463743" 
$shm_file = "/dev/shm/$shm_id.tmp"; #set filename in tempfs 
$| = 1; #suffering from buffering 
print ("Activity Indicator: "); #No new line here 
defined(my $pid = fork) or die "Couldn't fork: $!"; 
if (!$pid) { # Child 
    @stdoutput=`/usr/home/script.pl -o $parameter`; #get output of external command 
    open (SHM, ">$shm_file"); 
    foreach (@stdoutput) { 
     print SHM ("$_"); #populate file in tempfs 
    } 
    close (SHM);   
    exit; #quit the child process (will not kill parent script) 
} else { # Parent 
    while (! waitpid($pid, WNOHANG)) { 
    print ("\#"); # prints a progress bar 
     sleep 5; 
    } 
} 
print ("\n"); #finish up bar and go to new line 
open (SHM, "$shm_file"); 
    @stdoutput = <SHM>; #Now open the file and read it. Now array is in parent 
close (SHM); 
unlink ($shm_file); #deletes the tempfs file 
chomp(@stdoutput); 
foreach (@stdoutput) { 
    print ("$_\n"); #print results of external script 
}