我发布我的代码只是为了我的问题的上下文。我并没有明确地寻找你来帮助解决它,我更期望理解dup2系统调用,我只是从手册页和许多其他的stackoverflow问题中找不到。了解dup2和关闭文件描述符
pid = fork();
if(pid == 0) {
if(strcmp("STDOUT", outfile)) {
if (command->getOutputFD() == REDIRECT) {
if ((outfd = open(outfile, O_CREAT | O_WRONLY | O_TRUNC)) == -1)
return false;
command->setOutputFD(outfd);
if (dup2(command->getOutputFD(), STDOUT_FILENO) == -1)
return false;
pipeIndex++;
}
else if (command->getOutputFD() == REDIRECTAPPEND) {
if ((outfd = open(outfile, O_CREAT | O_WRONLY | O_APPEND)) == -1)
return false;
command->setOutputFD(outfd);
if (dup2(command->getOutputFD(), STDOUT_FILENO) == -1)
return false;
pipeIndex++;
}
else {
if (dup2(pipefd[++pipeIndex], STDOUT_FILENO) == -1)
return false;
command->setOutputFD(pipefd[pipeIndex]);
}
}
if(strcmp("STDIN", infile)) {
if(dup2(pipefd[pipeIndex - 1], STDIN_FILENO) == -1)
return false;
command->setOutputFD(pipefd[pipeIndex - 1]);
pipeIndex++;
}
if (execvp(arguments[0], arguments) == -1) {
std::cerr << "Error!" << std::endl;
_Exit(0);
}
}
else if(pid == -1) {
return false;
}
对于您的上下文,该代码表示基本Linux shell的执行步骤。命令对象包含命令参数,IO“名称”和IO描述符(我想我可能会将文件描述符作为字段除去)。
我最难理解的是什么时候和哪个文件描述符关闭。我想我会问一些问题,试图提高我对这个概念的理解。
1)使用我用于处理管道的文件描述符数组,父级拥有所有这些描述符的副本。父母持有的描述符何时关闭?甚至更多,哪些描述符?是全部吗?所有这些都未被执行命令使用?
2)在处理子级内的管道时,哪些描述符由哪些进程保持打开状态?说如果我执行命令:ls -l | grep “[username]”,应该为ls进程保留哪些描述符?只是管道的写入结束?如果是的话?同样的问题适用于grep命令。
3)当我处理IO重定向到一个文件时,必须打开一个新文件并将其缓存到STDOUT(我不支持输入重定向)。这个描述符什么时候关闭?我在例子中看到,它在调用dup2之后立即关闭,但是如果文件已关闭,那么文件如何写入文件?
提前致谢。我一直被困在这个问题上好几天,我真的很想完成这个项目。
编辑我曾与修改后的代码和样本输出更新了这个有兴趣的人提供具体的帮助我的问题。首先我有整个处理执行的for循环。它已更新,我的电话关闭各种文件描述符。
while(currCommand != NULL) {
command = currCommand->getData();
infile = command->getInFileName();
outfile = command->getOutFileName();
arguments = command->getArgList();
pid = fork();
if(pid == 0) {
if(strcmp("STDOUT", outfile)) {
if (command->getOutputFD() == REDIRECT) {
if ((outfd = open(outfile, O_CREAT | O_WRONLY | O_TRUNC)) == -1)
return false;
if (dup2(outfd, STDOUT_FILENO) == -1)
return false;
close(STDOUT_FILENO);
}
else if (command->getOutputFD() == REDIRECTAPPEND) {
if ((outfd = open(outfile, O_CREAT | O_WRONLY | O_APPEND)) == -1)
return false;
if (dup2(outfd, STDOUT_FILENO) == -1)
return false;
close(STDOUT_FILENO);
}
else {
if (dup2(pipefd[pipeIndex + 1], STDOUT_FILENO) == -1)
return false;
close(pipefd[pipeIndex]);
}
}
pipeIndex++;
if(strcmp("STDIN", infile)) {
if(dup2(pipefd[pipeIndex - 1], STDIN_FILENO) == -1)
return false;
close(pipefd[pipeIndex]);
pipeIndex++;
}
if (execvp(arguments[0], arguments) == -1) {
std::cerr << "Error!" << std::endl;
_Exit(0);
}
}
else if(pid == -1) {
return false;
}
currCommand = currCommand->getNext();
}
for(int i = 0; i < numPipes * 2; i++)
close(pipefd[i]);
for(int i = 0; i < commands->size();i++) {
if(wait(status) == -1)
return false;
}
执行此代码时我收到以下输出
ᕕ(ᐛ)ᕗ ls -l
total 68
-rwxrwxrwx 1 cook cook 242 May 31 18:31 CMakeLists.txt
-rwxrwxrwx 1 cook cook 617 Jun 1 22:40 Command.cpp
-rwxrwxrwx 1 cook cook 9430 Jun 8 18:02 ExecuteExternalCommand.cpp
-rwxrwxrwx 1 cook cook 682 May 31 18:35 ExecuteInternalCommand.cpp
drwxrwxrwx 2 cook cook 4096 Jun 8 17:16 headers
drwxrwxrwx 2 cook cook 4096 May 31 18:32 implementation files
-rwxr-xr-x 1 cook cook 25772 Jun 8 18:12 LeShell
-rwxrwxrwx 1 cook cook 243 Jun 5 13:02 Makefile
-rwxrwxrwx 1 cook cook 831 Jun 3 12:10 Shell.cpp
ᕕ(ᐛ)ᕗ ls -l > output.txt
ls: write error: Bad file descriptor
ᕕ(ᐛ)ᕗ ls -l | grep "cook"
ᕕ(ᐛ)ᕗ
的ls -l > output.txt
输出意味着,我关闭了错误的描述,但关闭其他相关描述符,而渲染没有错误,提供没有输出到文件。如ls -l
,grep "cook"
所示,应该生成输出到控制台。
感谢您对dup2系统调用的详细解答。但是在关闭我认为合适的文件描述符之后,我仍然无法让dup2正常运行。我绝对想要独自完成这个项目,但我真的迷失在这里。我已经更新了原始文章,并提供了样本和更新的代码,如果您可以检查并提供更有针对性的建议。 再次,谢谢。我更好地理解函数调用,但我仍然无法将其应用于上下文中。 – MichaelCook
@MichaelCook请检查更新后的答案。 –