gpt4 book ai didi

c++ - 在 C++ 中使用 posix pipe() 和 dup() 来重定向 I/O 问题

转载 作者:太空狗 更新时间:2023-10-29 23:08:52 25 4
gpt4 key购买 nike

我必须修改我为之前的家庭作业编写的一个简单的 shell 来处理 I/O 重定向,但我在让管道工作时遇到了问题。似乎当我在分离进程中复制文件描述符后写入和读取 stdout 和 stdin 时,管道工作,但如果我使用 printf、fprintf、gets、fgets 等任何东西来尝试查看输出是否是出现在管道中,即使 stdin 和 stdout 的文件描述符显然是管道的拷贝,它也会进入控制台(我不知道这是否是正确的表达方式,但我认为这一点很明确) .

我 99.9% 确定我正在做所有事情,至少在纯 C 中应该如此——例如在 dup() 之后适本地关闭所有文件描述符——并且文件 I/O 工作正常,所以这看起来就像我不知道也找不到任何信息的细节问题。我一天中的大部分时间都在尝试不同的事情,过去几个小时我在谷歌上搜索,试图弄清楚我是否可以将 cin 和 cout 重定向到管道,看看是否能解决它,但似乎麻烦多于它的值(value)这点。

因为 cin 和 cout 应该与 stdio 同步,是否应该仅通过重定向 stdin 和 stdout 来工作?我认为应该这样做,尤其是因为这些命令可能是用 C 语言编写的,所以我认为它们会使用 stdio。但是,如果我尝试“cat [file1] [file2] | sort”之类的命令,它会将 cat [file1] [file2] 的结果打印到命令行,并且排序不会获得任何输入,因此它没有输出。也很明显 cout 和 cin 也不受 dup() 的影响,所以我把两个和两个放在一起得出这个结论这是我的代码的一个稍微缩短的版本,去掉了所有错误检查和类似的东西,我相信我处理得很好。如果需要的话,我可以发布完整的代码,但它太多了,所以我将从这里开始。

我重写了该函数,以便父进程为每个命令 fork 出一个子进程,并根据需要将它们与管道连接起来,然后等待子进程结束。同样,在文件描述符 0 和 1 上写入和读取工作(即写入管道和从管道读取),FILE 指针 stdin 和 stdout 上的 stdio 不起作用(不写入管道)。

非常感谢,这让我很苦恼...

更新:我没有为每个不同的命令更改字符串 cmd,所以它似乎没有工作,因为管道只是转到相同的命令,所以最终输出是相同的......抱歉,我很笨, 但谢谢,因为我发现了 strace 的问题。

int call_execv( string cmd, vector<string> &argv, int argc,
vector<int> &redirect)
{
int result = 0, pid, /* some other declarations */;
bool file_in, file_out, pipe_in, pipe_out;
queue<int*> pipes; // never has more than 2 pipes

// parse, fork, exec, & loop if there's a pipe until no more pipes
do
{
/* some declarations for variables used in parsing */
file_in = file_out = pipe_in = pipe_out = false;

// parse the next command and set some flags
while( /* there's more redirection */ )
{
string symbol = /* next redirection symbol */

if( symbol == ">" )
{
/* set flags, get filename, etc */
}
else if( symbol == "<" )
{
/* set flags, get filename, etc */
}
else if( pipe_out = (symbol == "|") )
{
/* set flags, and... */
int tempPipes[2];
pipes.push( pipe(tempPipes) );
break;
}
}

/* ... set some more flags ... */

// fork child
pid = fork();
if( pid == 0 ) // child
{
/* if pipe_in and pipe_out set, there are two pipes in queue.
the old pipes read is dup'd to stdin, and the new pipes
write is dup'd to stdout, other two FD's are closed */

/* if only pipe_in or pipe_out, there is one pipe in queue.
the unused end is closed in whichever if statement evaluates */

/* if neither pipe_in or pipe_out is set, no pipe in queue */

// redirect stdout
if( pipe_out ){
// close newest pipes read end
close( pipes.back()[P_READ] );

// dup the newest pipes write end
dup2( pipes.back()[P_WRITE], STDOUT_FILENO );

// close newest pipes write end
close( pipes.back()[P_WRITE] );
}
else if( file_out )
freopen(outfile.c_str(), "w", stdout);

// redirect stdin
if( pipe_in ){
close( pipes.front()[P_WRITE] );
dup2( pipes.front()[P_READ], STDIN_FILENO );
close( pipes.front()[P_READ] );
}
else if ( file_in )
freopen(infile.c_str(), "r", stdin);


// create argument list and exec
char **arglist = make_arglist( argv, start, end );
execv( cmd.c_str(), arglist );

cout << "Execution failed." << endl;
exit(-1); // this only executes is execv fails

} // end child

/* close the newest pipes write end because child is writing to it.
the older pipes write end is closed already */
if( pipe_out )
close( pipes.back()[P_WRITE] );

// remove pipes that have been read from front of queue
if( init_count > 0 )
{
close( pipes.front()[P_READ] ); // close FD first
pipes.pop(); // pop from queue
}

} while ( pipe_out );

// wait for each child process to die

return result;
}

最佳答案

无论出现什么问题,您都没有检查任何返回值。您如何知道 pipe()dup2() 命令是否成功?您是否已验证 stdoutstdin 确实指向 execv 之前的管道? execv 是否保留您提供的文件描述符?不确定,这是 execve 文档中的相应段落:

  • 默认情况下,文件描述符在 execve() 中保持打开状态。标记为 close-on-exec 的文件描述符被关闭;请参阅 fcntl(2) 中对 FD_CLOEXEC 的描述。 (如果一个 文件描述符关闭,这将导致释放此进程在基础文件上获得的所有记录锁。有关详细信息,请参阅 fcntl(2)。)POSIX.1-2001 说 如果文件描述符 0、1 和 2 在成功执行 execve() 后关闭,并且进程将获得特权,因为 set-user_ID 或 set-group_ID 每个 在执行的文件上设置了任务位,那么系统可能会为这些文件描述符中的每一个打开一个未指定的文件。作为一般原则,没有可移植程序, 无论是否有特权,都可以假设这三个文件描述符将在 execve() 期间保持关闭状态。

您应该添加更多调试输出,看看到底发生了什么。您是否在程序中使用了 strace -f(跟踪 child )?

关于c++ - 在 C++ 中使用 posix pipe() 和 dup() 来重定向 I/O 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7886067/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com