in reply to Cheapest way for multiple external commands

Is there any way to prevent that "fork"?

AFAIK, no. See exec, system, and qx.

i need to run many externals commands from my Perl script and capture both return-code and STDOUT. These commands must run under a shell...

Be aware of The problem of "the" default shell. I also wrote about running external commands here. In this case I'd suggest something like IPC::System::Simple (note it doesn't capture STDERR, for that I'd suggest a different module):

use IPC::System::Simple qw/capturex EXIT_ANY/; my $out = capturex '/bin/bash', '-c', 'echo foo'; # or, if you don't want it to die on nonzero exit: my $out2 = capturex EXIT_ANY, '/bin/bash', '-c', 'echo bar && false';
i am looking for the "cheapest way" in terms of CPU and Memory load...

Without more information, this smells like premature optimization. What OS? What commands are you running; could they perhaps be replaced by Perl code? How many commands per second are you running? How fast do you need it to run, and have you written a prototype and measured its performance to see if it's good enough or not?

Replies are listed 'Best First'.
Re^2: Cheapest way for multiple external commands
by pedrete (Sexton) on Jan 27, 2020 at 09:56 UTC
    Thanks everybody.... i was just looking for to prevent the "fork" but i am afraid it is un-avoidable...
      Looking to avoid the fork indicates you don’t quite have a handle on Unix process design. It is impossible to start another process on Unix without first forking a program; the child process then calls exec to become the other program of your choice. there is no equivalent to Win32 CreateProcess (though you could use inter-process communication to ask some other daemon to fork/exec for you)

      What it sounds like you actually want to avoid is the call to “wait” that blocks the parent process until the child has ended. The module IPC::Run is a good way to run asynchronous processes and capture their output.

        It is impossible to start another process on Unix without first forking a program; the child process then calls exec to become the other program of your choice.

        Not quite right. You can simply call exec() without a previous fork() to replace your current program with a new one, or a fresh run of the current one. Both are common techniques. Chained exec() is e.g. used by sudo, chroot, getty, login, massively by daemontools and frieds (see Re^3: Daemon::Control pid-files and Re^5: RFC: an(other) UNIX daemon module implementation). Self-exec() is commonly used by daemons that want to reload their configuration or just want to forget about everything they have done so far.

        there is no equivalent to Win32 CreateProcess

        And that's a good thing! See Re^3: Set env variables as part of a command. CreateProcess() takes more than 30 parameters, its more advanced relatives take even more. fork() needs no parameters at all, exec() takes program name and arguments, the lower-level execve() system call also takes program name, arguments and a pointer to the environment. Every other aspect of the child process can be changed between fork() and exec(), without inflating any other function to take a ridiculous amount of parameters.

        Also note that you don't have to call exec() after fork(). A common use are network daemons like sshd or telnetd that fork a new process for each new connection. Another use is to create one child process per task, this happens in PostgreSQL (see Re^2: Setting $0 clears /proc/PID/environ too).

        An advanced use is privilege separation: Assume you have to analyze (parse) some data passed in from the network while running as root. Call fork() to create a child process. Isolate the child process in an empty directory (chroot() or jail()), set resource limits, drop privileges, close all file handles except for a way to send your result back to the privileged process. If you run on modern *BSDs, disable all system calls that this process won't need any more. Start chewing on the data from the network. exit() with a nonzero exit code if something looks fishy. At the same time, have the parent set up a timeout that kills the child process unconditionally and forcefully (kill(child, SIGKILL)). Call wait() or waitpid() to wait for the isolated process. If its exit code is not null, assume something went wrong and do not touch the data from the network any more. Discard it, disconnect the network connection.

        Try to do that with CreateProcess() and its ugly relatives!


        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)