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

Oh, Wisest ones:

I have a parent thread who forks a child which executes a script with exec, after a time, it kills such child (using the pid of the child forked)

This works wonderfuly

my $pidChild; my $pid0=fork(); if ($pid0) { #parent process $pidChild=$pid0; print "Parent has launched child $pid0\n"; sleep(10); my $killed=kill 'KILL', $pidChild; if ($killed) { print "Parent has killed child $pid0\n"; } sleep(5); my @alive=`ps aux | grep process | grep -v grep`; print "@alive\n"; } else { #child print "This is child $$\n"; my $command='sh /path/process.sh'; exec($command); }

until I try to redirect the output of the executed script, then the pid changes.

my $pidChild; my $pid0=fork(); if ($pid0) { #parent process $pidChild=$pid0; print "Parent has launched child $pid0\n"; sleep(10); my $killed=kill 'KILL', $pidChild; if ($killed) { print "Parent has killed child $pid0\n"; } sleep(5); my @alive=`ps aux | grep process | grep -v grep`; print "@alive\n"; } else { #child print "This is child $$\n"; my $command='sh /path/process.sh 2>&1'; exec($command); }

Also fails if I try to redirect the output to a file

my $command='sh /path/process.sh > /pathlogs/mylog.log';

Why the redirection changes the pid? Are the script I am trying to execute and the redirection of its output different processes? What is it happening inside there?

Thank you a lot in advance for clarifying this mistery...

Replies are listed 'Best First'.
Re: fork, exec and pid
by Corion (Patriarch) on Oct 25, 2015 at 19:54 UTC

    See exec:

    If there is more than one argument in LIST, this calls execvp(3) with the arguments in LIST. If there is only one element in LIST, the argument is checked for shell metacharacters, and if there are any, the entire argument is passed to the system's command shell for parsing (this is /bin/sh -c on Unix platforms, but varies on other platforms).

    What you get is your child PID, but the command is run through an intermediate shell, which then executes another shell.

    You will need to either implement all the redirection yourself and use the list form of exec or write the command(s) to a shell script and exec that shell script. Some shells also can take a list of commands or a pipeline on their commandline, so maybe directly using the list form works too:

    exec "/bin/sh", "/path/process.sh > /pathlogs/mylog.log";

      Thanks a lot for the clarification, I have finally decided to implement the redirection myself and skip the intermediate shells:

      #child print "This is child $$\n"; open STDERR, '>&STDOUT'; open STDOUT, '> /pathlogs/mylog.log'; my $command='sh /path/process.sh'; exec($command);

      This way, killing the pid of the child, we kill the command process and I also get the redirections.

      It also seems to work with

      #child print "This is child $$\n"; open STDERR, '>&STDOUT'; open STDOUT, '> /pathlogs/mylog.log'; my $script='/soft/perl-version/bin/perl /path/process.pl'; exec($script);

      I will clearly have to research more to use correctly exec and pid managing :)