So long story short, I'm trying to run a linux perl script in Windows ( with few modifications ).
On Unix it works just fine, but on Windows I come to the conclusion that calling for system doesn't work the same as on Unix and so it doesn't create multiple processes.
Below is the code :
use strict;
use warnings;
open (FIN, 'words.txt'); while (<FIN>) {
chomp;
my $line = $_;
system( "perl script.pl $line &" );
}
close (FIN);
So basically, I have 5 different words in "words.txt" which I want each and every one to be used one by one when calling for script.pl , which means :
word1 script.pl
word2 script.pl
word3 script.pl
etc
As of now it opens just the first word in words.txt and it loops with that one only. As I said, on Unix it works perfectly, but not on Windows.
I've tried to use "start" system( "start perl script.pl $line &" ); and it works...except it opens 5 additional CMDs to do the work. I want it to do the work on the same window.
If anyone has any idea how this can work on window, i'll really appreciate it.
Thanks!
CodePudding user response:
According to perlport :
system
(Win32) [...]
system(1, @args)
spawns an external process and immediately returns its process designator, without waiting for it to terminate. Return value may be used subsequently inwait
orwaitpid
. Failure tospawn()
a subprocess is indicated by setting$?
to 255 << 8.$?
is set in a way compatible with Unix (i.e. the exit status of the subprocess is obtained by$? >> 8
, as described in the documentation).
I tried this:
use strict;
use warnings;
use feature qw(say);
say "Starting..";
my @pids;
for my $word (qw(word1 word2 word3 word3 word5)) {
my $pid = system(1, "perl script.pl $word" );
if ($? == -1) {
say "failed to execute: $!";
}
push @pids, $pid;
}
#wait for all children to finish
for my $pid (@pids) {
say "Waiting for child $pid ..";
my $ret = waitpid $pid, 0;
if ($ret == -1) {
say " No such child $pid";
}
if ($? & 127) {
printf " child $pid died with signal %d\n", $? & 127;
}
else {
printf " child $pid exited with value %d\n", $? >> 8;
}
}
say "Done.";
With the following child script script.pl
:
use strict;
use warnings;
use feature qw(say);
say "Starting: $$";
sleep 2 int(rand 5);
say "Done: $$";
sleep 1;
exit int(rand 10);
I get the following output:
Starting..
Waiting for child 7480 ..
Starting: 9720
Starting: 10720
Starting: 9272
Starting: 13608
Starting: 13024
Done: 13608
Done: 10720
Done: 9272
Done: 9720
Done: 13024
child 7480 exited with value 9
Waiting for child 13344 ..
child 13344 exited with value 5
Waiting for child 17396 ..
child 17396 exited with value 3
Waiting for child 17036 ..
child 17036 exited with value 6
Waiting for child 17532 ..
child 17532 exited with value 8
Done.
Seems to work fine..
CodePudding user response:
You can use Win32::Process
to get finer control over creating a new process than system
gives you on Windows. In particular, the following doesn't create a new console for each process like using system("start ...")
does:
#!/usr/bin/env perl
use warnings;
use strict;
use feature qw/say/;
# Older versions don't work with an undef appname argument.
# Use the full path to perl.exe on them if you can't upgrade
use Win32::Process 0.17;
my @lines = qw/foo bar baz quux/; # For example instead of using a file
my @procs;
for my $line (@lines) {
my $proc;
if (!Win32::Process::Create($proc, undef, "perl script.pl $line", 1,
NORMAL_PRIORITY_CLASS, ".")) {
$_->Kill(1) for @procs;
die "Unable to create process: $!\n";
}
push @procs, $proc;
}
$_->Wait(INFINITE) for @procs;
# Or
# use Win32::IPC qw/wait_all/;
# wait_all(@procs);
As Yet Another Way To Do It, the start
command takes a /b
option to not open a new command prompt.
system("start /b perl script.pl $line");