First, let's be aware of what is being executed.
system($shell_command)
is short for
system({ "/bin/sh" } "/bin/sh", "-c", $shell_command)
unless the shell command contains no shell meta-characters but whitespace, in which case
system($shell_command)
is short for
my @cmd = split(' ', $shell_command);
system({ $cmd[0] } @cmd)
As such,
system("child.pl 'dummy'") is short for system({ "/bin/sh" } "/bin/sh", "-c", "child.pl 'dummy'")
system("child.pl") is short for system({ "child.pl" } "child.pl")
system("bash -c child.pl") is short for system({ "bash" } "bash", "-c", "child.pl")
system("sh -c child.pl") is short for system({ "sh" } "sh", "-c", "child.pl")
Of note is that bash
replaces itself with child.pl
instead of spawning it in a separate process in this particular circumstance. That makes child.pl
a direct child of parent.pl
in the third case (just like the second case).
Second, let's be aware of what Ctrl-C does.
When Ctrl-C is pressed, the terminal sends SIGINT to every process that has that terminal as its controlling terminal. In other words, SIGINT is sent to every process of the session.
As you can see by adding system("ps -o pid,ppid,pgrp,sid,cmd");
to child.pl
, there are three or four processes in our session depending on the test case.
child.pl
: child.pl
handles SIGINT. It isn't killed by it.
- The shell started by
parent.pl
in test cases 1 and 4: The shell is killed by SIGINT.
parent.pl
: system
does the equivalent of local $SIG{INT} = 'IGNORE';
, so it ignores SIGINT.
- The login shell that started
parent.pl
: It ignores SIGINT, but I'm not sure why. I'm guessing it's because it's an interactive shell.
So, this is what you are observing:
- When the (direct) child of
parent.pl
is child.pl
[Test cases 2 and 3], the child (child.pl
) does not die from SIGINT since it handles SIGINT.
- When the (direct) child of
parent.pl
is a shell [Test cases 1 and 4], the child (the shell) dies from SIGINT since non-interactive shells don't handle/ignore SIGINT.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…