Processes, Signals and IPC
36.1 Running External Commands
use v5.36;
system('ls', '-l', '/tmp') == 0 or die "ls failed: $?"; # list form: no shell (safe)
my $exit = $? >> 8;
my $output = `uname -a`; # backticks: capture stdout (uses the shell)
my @lines = qx(git log --oneline -5);
exec('vim', 'file.txt'); # replace the current process (never returns)
# Pipes
open my $ps, '-|', 'ps', 'aux' or die $!; # read from a command (list form, no shell)
while (<$ps>) { print if /perl/ }
close $ps;
open my $mail, '|-', '/usr/sbin/sendmail', '-t' or die $!; # write to a command
# Capture stdout, stderr, and the exit code safely (CPAN)
use Capture::Tiny qw(capture);
my ($stdout, $stderr, $exit_code) = capture { system('make', 'test') };
use IPC::Run3; run3(['grep', 'x'], \$in, \$out, \$err);
use IPC::Cmd qw(run can_run); # core
use IPC::Open3; # core, low level36.2 fork, wait and Signals
my $pid = fork() // die "fork failed: $!";
if ($pid == 0) { # child
say "Child $$ working";
exit 0;
}
waitpid($pid, 0); # parent waits
say "Child exited with ", $? >> 8;
$SIG{INT} = sub { say "Caught SIGINT, cleaning up"; exit 1 };
$SIG{TERM} = 'IGNORE';
eval { # timeout pattern
local $SIG{ALRM} = sub { die "timeout\n" };
alarm 5;
long_operation();
alarm 0;
1;
} or do {
die $@ unless $@ eq "timeout\n"; # rethrow unrelated errors
warn "Timed out\n";
};
$SIG{CHLD} = 'IGNORE'; # auto-reap children (on most Unix systems)
kill 'TERM', $pid;
local $SIG{__WARN__} = sub { ... };36.3 IPC Mechanisms
Pipes (pipe(my $r, my $w)), socketpairs, named pipes (mkfifo), System V IPC (IPC::SysV, shared memory, semaphores), files with flock, Unix domain sockets, message queues (Redis, RabbitMQ via Net::AMQP::RabbitMQ, ZeroMQ via ZMQ::FFI).
36.4 Daemons
use POSIX qw(setsid);
sub daemonize {
chdir '/';
open STDIN, '<', '/dev/null'; open STDOUT, '>', '/dev/null';
defined(my $pid = fork) or die "Can't fork: $!";
exit if $pid;
setsid() or die "Can't start a new session: $!";
open STDERR, '>&', \*STDOUT;
}
# Modern approach: don't daemonize yourself; run in the foreground under systemd/supervisord/Docker.
# CPAN: Proc::Daemon, Daemon::Control, Proc::PID::File