操作系统:Windows 11
Cp:GCC 11.4.0
硬件:英特尔
我有一个从 shell 程序中提取的示例。我正在尝试执行多个由 & '分隔'的程序。给定一个固定的字符串数组,这些字符串是有效的 bash,命令参数由“&”分隔,我应该能够并行分叉和执行所有单独的程序调用。不幸的是,我在分叉时遇到退出状态 0x3(无法打开指定的路径)。我不确定这是从哪里来的,也不知道为什么。
下面是我的原始程序的简化版本。首先,构建程序数组,然后将其传递给“execute_programs”函数,该函数将分叉并执行每个新的有效调用。对“execv”的调用可以忽略,但我保留它是为了显示完整的图片。在此示例中,仅发生一个分叉。我收到输出,
PID -1 的子进程退出,状态为 0x3。
我不明白为什么会发生这种情况。可能还有其他错误,但这个结果对我来说完全出乎意料且难以捉摸。我希望得到一些帮助。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/wait.h>
int execute_programs(int argc, char *argv[])
{
int n = 0;
int cnt = 0;
int current_cnt = 0;
while (argv[cnt] != NULL && cnt < argc)
{
if (strcmp(argv[cnt], "&") == 0)
{
// Block the array.
argv[cnt] = NULL;
// Update variables.
n++; // Number of programs grows.
current_cnt = 0; // Number of current arguments goes back to zero.
if (current_cnt > 0) // There is an adequate number of child processes.
{
// Start child process.
pid_t rc;
if ((rc = fork()) < 0)
{
// There was an error.
abort();
}
else if (rc == 0)
{
// Run the i'th process.
// printf("%d\n", execv(argv[cnt - current_cnt], &argv[cnt]));
exit(0);
}
}
}
current_cnt++; // Increment number of current arguments.
cnt++; // Increment count;
}
/* Wait for children to exit. */
int status;
pid_t pid;
while (n > 0)
{
pid = wait(&status);
printf("Child with PID %ld exited with status 0x%x.\n", (long)pid, status);
--n;
}
// return;
return 0;
}
int main(int argc, char *argv[])
{
char *programs[5];
programs[0] = strdup("echo");
programs[1] = strdup("\"ah\"");
programs[2] = strdup("&");
programs[3] = strdup("ls");
programs[4] = NULL;
execute_programs(5, programs);
return 0;
}
编辑:“execv”调用被注释掉,因为我可能没有正确使用它。尽管如此,如果没有它,错误就会发生。给出了相同的错误消息。
这篇文章让我想起了几年前我在
getopt()
函数中遇到的一个问题,该函数需要 argc
和 argv
就像 execv()
一样。我得出的结论是每个参数字符串应该在连续的字符数组中,但我找不到官方文档这么说。
int main(int argc, char *argv[]) {
char cmd_buffer[256];
snprintf(cmd_buffer, sizeof(cmd_buffer),
R"(echo\0"ah"&\0ls)"); // echo "ah" & ls -> continuous string
// 0 0 0 -> null-terminate
// 0123456789abcd -> index
char *programs[5];
programs[0] = &cmd_buffer[0];
programs[1] = &cmd_buffer[5];
programs[2] = &cmd_buffer[9];
programs[3] = &cmd_buffer[11];
programs[4] = NULL;
execute_programs(5, programs);
return 0;
}
我在 WSL 上测试了上面的代码,它没有打印任何错误消息,而原始代码打印“Child with PID -1 exited with status 0x3”;
您需要做的是在单个 char 数组中构建一个以 null 结尾的参数,并将 argv 设置为指向每个参数的开头。