【发布时间】:2024-01-06 04:41:01
【问题描述】:
我正在尝试在不同平台上并行运行几个子进程。只有在所有子进程在各自平台上完成后,父进程才应继续进行。
问题是当我使用 fork 然后在子进程中运行“exec”命令时,它几乎立即结束。此外,输出不一致。几乎每次日志只显示一行。
-bash-2.05b$ cat Agent.SOLSPARC
caught SIGTERM signal, cleaning up
或
-bash-2.05b$ cat Agent.SOLSPARC
Host: EBSO9SPC Login: esm2
有时,有几行多余的行,最后是消息,'被信号 15 杀死'。我在“exec”中使用的命令实际上调用了一个脚本,该脚本连接到远程盒子并在它们上运行 make 命令。出于测试目的,我目前只通过一个平台,即 SOLSPARC。另外,我只想知道命令是否在任何给定平台上完成。
我不确定我是否正确地将所有参数传递给了“exec”,所以我尝试了不同的组合(在参考了 Internet 上的不同链接之后)但无济于事。一个重要的观察结果是,当我使用 strace 调试此问题时,该命令运行良好。我在 perldoc 中看到 exec 在 Unix 平台上使用 /bin/sh -c ,但在其他平台上有所不同。是不是exec和strace使用了不同的shell?
这是我的代码的相关部分:
sub compile {
my %child_pids;
foreach $plat (0 .. $#plat_list) {
my $pid = fork;
# Didn't check the undef condition for child
if ($plat_list[$plat] eq "SOLSPARC") {
print "\nStarted Solaris build \n";
if ($pid == 0) {
print "Inside Child Process \n\n";
exec ( "${ROOT}/${REM_EXEC} -t 1200 -c \"make LANG=en_US distclean \" -b ${ROOT} -l Agent. $plat_list[$plat]" ) or die "exec failed";
} elsif ($pid > 0) {
$child_pids{"SOLSPARC"} = $pid;
}
} else {
print "\nStarted build for other platforms \n";
if ($pid == 0) {
print "Inside Child Process \n\n";
exec ( "${ROOT}/${REM_EXEC} -t 1200 -c \"make LANG=en_GB clean \" -b ${ROOT} -l Agent. $plat_list[$plat]" ) or die "exec failed";
} elsif ($pid > 0) {
$child_pids{"$plat_list[$plat]"} = $pid;
}
}
}
my %rev_child_pids = reverse %child_pids;
while ((my $kid = waitpid -1, WNOHANG) > 0) {
if ($rev_child_pids{$kid} eq "SOLSPARC") {
print "\nChild process completed for SOLARIS platform $rev_child_pids{$kid} \n";
print "Run some other command here \n";
} else {
print "\nChild process completed for other platform $rev_child_pids{$kid} \n";
print "No more commands to run \n";
}
}
}
有什么建议吗?
【问题讨论】:
-
您可能应该使用
exec的“列表形式”,传入参数列表而不是单个字符串。这样可以避免执行 shell 来运行命令。 -
只是添加到乔纳森的注释中,只有当你的命令行参数没有任何特殊的 shell 字符时,避免 shell 才有效,例如
<、|等... -
@DVK 是对的,但还有一个安全问题,如果你不小心
${ROOT}、${REM_EXEC}等变量,你最终可能会在你的代码。对于命令行脚本来说,这似乎不是什么大问题,但请考虑一下:假设${ROOT}是您自动获取的文件系统上的文件名,而该文件恰好被命名为“;rm -rf /*;",你可能对结果不满意。使用多参数 exec 可以避免这个特定问题。 -
我尝试了以下两种形式,但输出仍然没有变化。
exec ( "${ROOT}/${REM_EXEC}", "-t 1200", "-c \"make LANG=en_US distclean \"", "-b ${ROOT}", "-l Agent.", "$plat_list[$plat]" ) or die "exec failed";和exec ( "${ROOT}/${REM_EXEC}", "-t", "1200", "-c", "\"make LANG=en_US distclean \"", "-b", "${ROOT}", "-l", "Agent.", "$plat_list[$plat]" ) or die "exec failed";我以前也试过这些表格。 -
您需要向我们展示重现症状的最小完整代码。 (例如,您是否在某处生成 nmap?这可以解释“caught SIGTERM ...”消息。)