2
votes

open3 only takes STDIN, STDOUT and STDERR. If the command being run uses other file descriptors then open3 cannot capture those:

echo foo # Can be captured
echo foo >&2 # Can be catured
echo foo >&3 # Cannot be captured (with open3)

I have looked into IPC::Run::run which seems to be able to deal with that, but I also need the PID and I found no way for IPC::Run::run to give me that.

Is there an openN or a way for IPC::Run::run to give me the PID?

Background

This is intended for a possible extension of GNU Parallel, so you can do:

parallel 'echo {} start >&3;sleep 10;echo {} end >&3' ::: a b c 3>out.file

without having the output from different jobs mixed. GNU Parallel needs to keep track of each pid - especially when --keep-order is used.

1
Why do you want the pid?ikegami
IPC::Open3 doesn't stop you from putting a pipe on fd3. It just won't do it for you.ikegami
The child's pid is known in the IPC::Run internals. Just replace IPC::Run::run by IPC::Run::start and dump the returned object. Unfortunately this is not documented, so you're on your own...Slaven Rezic
@ikegami If you post an answer with echo {} start >&3;sleep 10;echo {} end >&3 as the command being run and fd3 assigned to a perl file handle, I will accept that as an answer.Ole Tange

1 Answers

0
votes

fd3 will already exist, so all you need to do is make sure the children inherit it. Since it's inherited itself, you shouldn't have to do anything at all.

$ perl -e'
   system "echo foo >&3";
' 3>bar

$ cat bar
foo

But if you want to make sure it's inherited, you can use the following

$ perl -e'
   use Fcntl qw( F_GETFD F_SETFD FD_CLOEXEC );
   if (open(my $fh, ">&=", 3)) {
      my $flags = fcntl($fh, F_GETFD, 0)
         or die $!;
      fcntl($fh, F_SETFD, $flags & ~FD_CLOEXEC)
         or die $!;
   }

   system "echo foo >&3";
' 3>bar

$ cat bar
foo