Seshouan has asked for the wisdom of the Perl Monks concerning the following question:

is there a way of getting the process ID of a process that you launch from a perl scrypt? I know that the backtick, exec(), and system() don't give you the PID of the process that they are launching. Is there another command that will?

Replies are listed 'Best First'.
Re: getting a child's process ID
by davorg (Chancellor) on Oct 19, 2001 at 19:19 UTC

    Well, backtick and system don't return until the child process has finished, so its PID would be of no use. exec replaces your process with the child process, so again you won't be able to use the PID as your program will no longer be running.

    fork returns the PID of the child to the parent and 0 to the child so that you can tell the difference between the two processes.

    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you don't talk about Perl club."

      I tried using fork(), it returns the PID of the fork, but not the process within the fork, that's what I want to exit. This is what I have:
      #!/usr/bin/perl -w use POSIX; if ($pid = fork) { # parent open(OUT,">Test.txt"); print OUT "The process: $pid\n"; close(OUT); } else { # child exec("emulator.exe"); exit(0); }
      the pid that is printed in the file is not that of the exec() call, that's what I'm interested in getting so that I can quit it.

        Looks to me like that should work as you want. Here's what I did to test it out:

        #!/usr/bin/perl -w # parent.pl use strict; if (my $pid = fork) { print "parent: child pid is $pid\n"; } else { exec('./child.pl'); } #!/usr/bin/perl -w # child.pl use strict; print "Child: pid is $$\n";

        And the output I got was:

        parent: child pid is 26534 Child: pid is 26534
        --
        <http://www.dave.org.uk>

        "The first rule of Perl club is you don't talk about Perl club."

        Seshouan, I just re-read the posts in this thread again, and enlightenment struck me like a ton of bricks (I think ;) Are you using ActivePerl on Windows? Because in that version of perl, process ID's don't stay the same across an exec() call. The PID is supposed to stay the same, and on Unix, it does; that's why davorg's example works and yours doesn't -- he tried his on Unix.

        The problem is, Win32 doesn't have a way to launch a new program without changing the PID. On Unix, exec() is an actual system call that loads a new program into a pre-existing process. On Win32, exec() is implemented by having the exec-ing process call CreateProcess, and then exit. So on Unix the $pid=fork trick works because the program you are exec-ing ends up in the child you created with fork, but on Windows, the program you exec ends up as a grandchild of the original process. Oops. That will make things a lot harder.

        I can think of two ways to solve this problem: (1) use Cygwin's Win32 perl instead of ActivePerl, or (2) hack together some kind of inter-process communication to let the parent process find out the child's pid. For example, pass the child a command-line argument that's a filename where it can write its pid once it starts up. Unfortunately, both these solutions require that you're in control of both the exec'd child and the parent. If not, there's probably still something you can do to get the child's pid, but I can't think of it off the top of my head. And of course all of this is irrelevant if you're not actually running on Win32. Anyway, good luck.

Re: getting a child's process ID
by blackmateria (Chaplain) on Oct 19, 2001 at 19:16 UTC
    If you're on *nix, fork() returns the child's pid to the parent, and 0 to the child. This works on Cygwin's Win32 port as well (not sure about ActivePerl).

    Update: Looks like it works on ActivePerl, too (at least build 613+).

Re: getting a child's process ID
by aijin (Monk) on Oct 19, 2001 at 19:19 UTC
    I think what you're looking for is fork. -aijin
Re: getting a child's process ID
by jlongino (Parson) on Oct 19, 2001 at 20:47 UTC
    I was wondering and maybe someone that replied earlier to this thread can tell me. Is there some way that the child can determine whether or not the parent process is still running (Active State Perl 5.6.x)? I'm familiar with doing this in a xnix environment with  getppid  but I know it's not available under ASP. I believe Seshouan was looking for similar information in a post yesterday as well.

    Thanks,

    --Jim

      Remember that at some point of the child's lifetime, it was the parent. Just do something along the lines of:

      #!/usr/bin/perl -w use strict; our $Parent_PID = $$; # ... Many interesting lines of code ... my $pid; # The mini-loop below will re-attempt the fork() # in case of errors, that are usually transient # resource shortages. You might not want to do this # in your scenario... while (($pid = fork()) < 0) { sleep 5; } if ($pid) { # Father print "father: the child is $pid\n"; # ... Interesting code to wait for the children ... } else { # Child print "child: My parent is $Parent_PID\n"; print "child: I am $pid (or $$)\n"; }
      Hope this helps you.
      jlongino -- much to my chagrin when working on Windows, Win32 doesn't have a (portable) getppid() equivalent. The closest equivalent is the Process32*() functions in the toolhelp library--these have a way of getting the parent pid. Unfortunately, they don't work on WinNT 4.0. Also, ActivePerl doesn't appear to use toolhelp (at least, a quick "grep -ir process32 *" from the root of my ActivePerl build 613 install didn't turn up anything). There might be a CPAN module that talks to toolhelp, I'm not sure. In any case, it's not portable.

      I'd say your best bet is to either use some form of inter-process communication (if you have control of the parent process), or else use the Cygwin version of perl instead of ActiveState if you can. getppid() works in that version. Also, beware of ActiveState's fork() -- it doesn't play very well with their implementation of sockets. I usually end up either using Cygwin or, for C programs, writing IPC code. Hope this helps!

      I don't do wintendo, so I can't answer as to how to find your parent's pid there. But if you've got the pid available you should be able to do kill 0 => $ppid to check. If that returns true then the process is still running. According to perldoc perlport this construct should work on wintendo.

Re: getting a child's process ID
by markdibley (Sexton) on Jan 09, 2015 at 13:11 UTC

    Sorry to revive this, but I have a problem with the way my code is working and it is related to this issue.

    I am using the same if...fork...else...exec process as @davorg but when I look at the ps -ef output I find 2 processes.

    if(my $pid = fork()){ $this->set_pid_in_db($id, $pid); } # Child process starts service and inherits child PID else{ my $command = sprintf("%s %s 1>>%s 2>>%s", $this->fnClient(), $id, + $this->fnOe($id), $this->fnOe($id)); #my $command = sprintf("%s %s", $this->fnClient(), $id); exec($command); } >ps -ef | grep SB mark 11970 1 0 07:57 pts/1 00:00:00 sh -c /code/SBClient2.pl j +ob1 1>>/log/log.1.oe 2>>/log/log.1.oe mark 11971 11970 77 07:57 pts/1 00:00:06 /usr/bin/perl /code/SBClie +nt2.pl job1

    And the PID that was set on line 2 is 11970 rather than 11971. Of course, I can still test to see if 11970 is running and that will tell me if 11971 is running. And I can kill 11970 and that will kill 11971.

    However, what confuses me is that if I don't redirect output and error to a file (i.e. use the commented out command instead), then 1 process rather than 2 processes are started.

    Does anyone know why this happens?

      If Perl finds something in the command line for exec or system that it can't interpret (like a redirection), it will invoke the shell to parse the command. This is what's happening here.

      As a solution, you could either do the redirect yourself by reopening STDERR to the file or restructure your approach so that you get the correct PID into the appropriate place.

        Thanks for the reply. The idea is to make this code independent of what it is running. It seems every day my argument for using perl gets weaker and weaker.