0

I have a piece of python code, that I need to convert it to perl, but unfortunately I am not good in perl, so sorry if the question is simple. I would like to check STDOUT and STDERR for a specific word. Here is the python code:

p = subprocess.Popen("bmod -b " + beginTime + " " + job_id + "; exit 1;", 
stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)

while p.poll() is None:
    err = p.stderr.readline().decode('utf_8')
    out = p.stdout.readline().decode('utf_8')
    if "changed" in err or "changed" in out:
        subprocess.Popen("echo rescheduling was successful!", shell=True)
os._exit(0)

I read some documentations and open3 function may work here, but for p.poll() part I am not sure what to use.

Azade Farshad
  • 1,022
  • 8
  • 18
  • 3
    There are several ways to read output from an external process in Perl, but the simplest are [`qx()`](http://perldoc.perl.org/perlop.html#qx%2f_STRING_%2f), [piped `open`](http://perldoc.perl.org/perlipc.html#Using-open%28%29-for-IPC), and [Capture::Tiny](https://metacpan.org/pod/Capture::Tiny). For `qx` and `open` you'll have to redirect STDERR since you want to check both STDOUT and STDERR. – ThisSuitIsBlackNot May 11 '16 at 14:30
  • 2
    `open3`+`select` is too low level. Use IPC::Run3's `run3` or IPC::Run's `run`. – ikegami May 11 '16 at 14:32
  • @ikegami Should I use something like this to wait for the output? `$pid = run3` or `$pid =open3` `wait($pid,0)` – Azade Farshad May 11 '16 at 14:43

1 Answers1

3

The answer depends on if it is important to print the message "rescheduling was successful!" immediately after a the line was printed from bmod (when bmod is still running) or if it is sufficient to print the line after bmod has exited.

The last case is a very simple to achieve in Perl, for example:

my $out = qx/bmod -b $beginTime $job_id 2>&1/;
say "rescheduling was successful!" if $out =~ /changed/;

Regarding the first case, if you need to print the message immediately (even before bmod has exited), first note that your Python script is probably not working correctly. The lines p.stderr.readline() will block the script until a line is ready to be read from p.stderr, similarly p.stdout.readline() will block the script until a line is ready to be read from p.stdout. So if bmod only prints to stdout and nothing goes to stderr, the script will hang at the first call to p.stderr.readline() and only return when bmod exits.

I am not sure how to do this correctly in Python, but in Perl you can use IPC::Open3 combined with IO::Select. See for example: Perl select return “bad file descriptor” error

Also note: A simpler solution in Perl can be achived using open if stderr and stdout are merged:

my $pid = open ( my $fh, '-|', "bmod -b $beginTime $job_id 2>&1" ) or die "Could not run command: $!";
while ( my $line = <$fh> ) {
     print $line if $line =~ /changed/;
}
close $fh;
Community
  • 1
  • 1
Håkon Hægland
  • 39,012
  • 21
  • 81
  • 174