为了实现shell命令解释器,我尝试执行管道。 要做到这一点,我使用递归函数,我使用管道函数和一些重定向与dup2。 这是我的代码:
void test_recurs(pid_t pid, char **ae)
{
char *const arg[2] = {"/bin/ls", NULL};
char *const arg2[3] = {"/bin/wc", NULL};
static int limit = 0;
int check;
int fd[2];
if (limit > 5)
return ;
if (pipe(fd) == -1)
{
printf("pipe failed\n");
return ;
}
pid = fork();
if(pid != 0)
{
printf("père %d\n",getpid());
close(fd[0]);
dup2(fd[1], 1);
close(fd[1]);
if ((execve("/bin/ls", arg, ae)) == -1)
exit(125);
dprintf(2, "execution ls\n");
wait(&check);
}
else
{
printf("fils %d\n", getpid());
close(fd[1]);
dup2(fd[0], 0);
close(fd[0]);
if ((execve("/bin/wc", arg2, ae)) == -1)
printf("echec execve\n");;
dprintf(2, "limit[%d]\n", limit);
limit++;
test_recurs(pid, ae);
}
}
问题是它只执行一次“ls | wc”然后等待标准输入。我知道问题可能来自管道(和重定向)。
答案 0 :(得分:2)
有点不清楚你是如何尝试使用你所提供的功能的,但这里有一些值得注意的一点:
依靠静态变量限制递归深度是不好的形式,因为它不是线程安全的,因为你需要做额外的工作来管理它(例如,确保当函数返回时,任何更改都会被撤消)。请改用函数参数。
正如在注释中所观察到的,exec-family函数仅在失败时返回。虽然你承认这一点,但我不确定你是否理解后果,因为你的fork的两个分支都包含永远不会被执行的代码。特别是递归调用已经死了,永远不会被执行。
此外,调用函数的过程本身会执行execve()
调用。函数未返回的原因是它将进程映像替换为新进程的。这意味着函数test_recurs()
也不会返回。
正如shell通常必须fork / exec来启动单个外部命令一样,它通常必须fork / exec来管道中的每个命令。如果它没有这样做,那么之后它就不再运行了 - 无论它执行什么,而不是分叉运行。
问题是它只执行" ls | WC"一次然后等待标准输入。
当然它没有递归,因为递归调用是在一段死代码中。我怀疑你错误地认为它后来等待标准输入,因为调用该函数的进程执行/bin/ls
,它不从标准输入读取。然而,当ls
退出时,既没有shell也没有ls
,那么你看到的东西似乎是在stdin上等待。