2

This answer explains how to get the pid of the new process when using Perl's exec(). The pid doesn't even change, so all you need to do is get the pid of the original script. But it doesn't work if I redirect the output to a file as part of the command, which I need to do.

say "my pid is $$";
exec("childscript.pl");                  # same pid

But if I redirect the output as part of the command:

say "my pid is $$";
exec("childscript.pl > log.txt");        # different pid, usually old pid + 1
exec("childscript.pl > log.txt 2>&1 &"); # same

then the new pid is one higher than the old one (which is probably just because they were spawned in succession and not reliable). I tested this both by looking at the output, and by inserting a sleep 30 into "childscript.pl" so that I could see it with ps -e.

My guess here is that redirecting the output causes a new process to do the writing. But I need the pid of the program, and I have no control over the program except for the fact that I can execute it. (It needs to run in the background too.)

1 Answer 1

5

When you call exec with a single argument (and that argument contains shell metacharacters), perl automatically runs sh -c ARG for you. In your case:

exec("childscript.pl > log.txt");
# really means:
exec("/bin/sh", "-c", "childscript.pl > log.txt");

I.e. your script loads sh into the currently running process, keeping its PID. The shell performs output redirection, then runs childscript.pl as a child process (with a new PID).

There are two ways to attack this problem:

  1. Do the output redirection in Perl and don't spawn a shell:

    open STDOUT, ">", "log.txt" or die "$0: log.txt: $!\n";
    exec "childscript.pl";
    die "$0: childscript.pl: $!\n";
    
  2. Tell the shell to also use exec and not spawn a child process:

    exec "exec childscript.pl > log.txt";
    die "$0: childscript.pl: $!\n";
    
Sign up to request clarification or add additional context in comments.

2 Comments

Excellent! Both methods work. Is there any one that's preferable for whatever reason? I suppose the second method relies on the shell having a compatible implementation of exec, but I would guess it's the same across *NIXes and like it because it's one line.
@felwithe, Involving the shell invokes a lot more work and a lot more things that can go wrong. Always opt for the option that removes unnecessary pieces.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.