我正在尝试在Linux中开发一个shell作为操作系统项目。其中一个要求是支持流水线操作(其中调用ls -l | less之类的东西将第一个命令的输出传递给第二个命令)。我正在尝试使用C pipe()和dup2()命令,但重定向似乎没有发生(少抱怨它没有收到文件名)。你能说出我哪里出错了/我该如何解决这个问题?
编辑:我认为我需要在某处使用freopen或fdopen,因为我没有使用read()或write()......这是正确的吗?(我听过其他人已经完成了这个项目,使用freopen()是另一种解决这个问题的方法;如果你认为那会更好,那么也可以理解这个方向的提示。)
这是我的execute_external()函数,它执行未内置到shell的所有命令。管道中的各种命令(例如[ls -l]和[less])存储在命令[]数组中。
void execute_external()
{
int numCommands = 1;
char **commands;
commands = malloc(sizeof(char *));
if(strstr(raw_command, "|") != NULL)
{
numCommands = separate_pipeline_commands(commands);
}
else
{
commands[0] = malloc(strlen(raw_command) * sizeof(char));
commands[0] = raw_command;
}
int i;
int pipefd[2];
for (i = 0; i < numCommands; i++)
{
char **parameters_array = malloc(strlen(commands[i]) * sizeof(char *));
int num_params;
num_params = str_to_str_array(commands[i], parameters_array);
if (numCommands > 1 && i > 0 && i != numCommands - 1)
{
if (pipe(pipefd) == -1)
{
printf("Could not open a pipe.");
}
}
pid_t pid = fork();
pmesg(2, "Process forked. ID = %i. \n", pid);
int status;
if (fork < 0)
{
fprintf(to_write_to, "Could not fork a process to complete the external command.\n");
exit(EXIT_FAILURE);
}
if (pid == 0) // This is the child process
{
if (numCommands > 1) { close(pipefd[1]); } // close the unused write end of the pipe
if (i == 0) // we may be pipelining and this is the first process
{
dup2(1, pipefd[1]); // set the source descriptor (for the next iteration of the loop) to this proc's stdout
}
if (i !=0 && (i != numCommands-1)) // we are pipelining and this is not the first or last process
{
dup2(pipefd[0], 0); // set the stdin of this process to the source of the previous process
}
if (execvp(parameters_array[0], parameters_array) < 0)
{
fprintf(to_write_to, "Could not execute the external command. errno: %i.\n", errno);
exit(EXIT_FAILURE);
}
else { pmesg(2, "Executed the child process.\n");}
}
else
{
if (numCommands > 1) { close(pipefd[0]); } // close the unused read end of the pipe
if (backgrounding == 0) { while(wait(&status) != pid); }// Wait for the child to finish executing
}
free(parameters_array);
}
free(commands);
}
答案 0 :(得分:1)
您的代码中似乎有一些错误。
首先,你所有的dup2只在孩子身上。为了连接管道,您需要将父级的stdout复制到管道的写入端pipefd [1]。然后你将把读端连接到stdin。
此外,看起来你的dup2是向后的,dup2 fildes被复制到fildes2。因此,当您重新分配stdin时,您需要dup2(in,0)和stdout,您需要dup2(out,1)。
所以一条简单的管道代码看起来像是:
int pipefd[2];
pipe(pipefd);
pid_t pid = fork();
if (pid == 0) //The child
{
dup2(pipefd[0], 0);
}
else
{
dup2(pipefd[1], 1);
}