好的,有十亿个演示与DUP,DUP2,FCNTL,管道和各种各样的东西是美妙的,当存在多个进程。然而,我还没有看到一个非常基本的东西,我认为这将有助于解释管道的行为及其与标准进出的关系。
我的目标是简单地(在同一个过程中)通过管道将标准输出直接重新路由到标准输出。我已经完成了
中间阶段将管道输出重定向到文件或写入缓冲区。。。然后把标准输出放回它开始的地方。在这一点上,我当然可以将缓冲区写回stdout,但我不想这样做。
由于我将标准输出移到了文件表中的另一个位置,所以我希望将管道的输出直接输入到新的标准输出位置,并让它像往常一样打印。
我觉得文件表周围有某种我不理解的层。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
int pipeEnds_arr1[2];
char str1[] = "STRING TO FEED INTO PIPE \n"; // make a string array
pipe(pipeEnds_arr1);
printf("File Descriptor for pipe ends from array\nPOSITION out 0 : %d\nPOSITION in 1 : %d\n", pipeEnds_arr1[0], pipeEnds_arr1[1]);
/* now my goal is to shift the input of the pipe into the position of
* standard output, so that the print command feeds the pipe, then I
* would like to redirect the other end of the pipe to standard out.
*/
int someInt = dup(1); // duplicates stdout to next available file table position
printf ("Some Int FD: %d\n", someInt); // print out the fd for someInt just for knowing where it is
/* This is the problem area. The out end of the pipe never
* makes it back to std out, and I see no way to do so.
* Stdout should be in the file table position 5, but when
* I dup2 the output end of the pipe into this position ,
* I believe I am actually overwriting std out completely.
* But I don't want to overwrite it, i want to feed the output
* of the pipe into std out. I think I am fundamentally
* misunderstanding this issue.
*/
dup2(pipeEnds_arr1[1], 1); //put input end of pipe into std out position
//dup2(pipeEnds_arr1[0], 5); // this will not work
//and other tests I have conducted do not work
printf("File Descriptor for pipe ends from array\nPOSITION out 0 : %d\nPOSITION in 1 : %d\n", pipeEnds_arr1[0], pipeEnds_arr1[1]);
fflush(stdout);
close(pipeEnds_arr1[0]);
close(pipeEnds_arr1[1]);
return 0;
}
编辑*********
好吧,我知道的是,std out从printf之类的命令中获取信息,然后将其路由到一个缓冲区,然后刷新到shell。
我相信一定有办法将管道的“读取”或输出端路由到同一个缓冲区,然后到达shell。我已经知道如何将管道输出路由到字符串中,然后我就可以随心所欲了。在下面的示例代码中,我将首先将管道路由到一个字符串,然后打开一个文件并将该字符串写入该文件的打开文件描述符。。。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
/* Each pipe end array has to have 2 positions in it. The array
* position represents the two pipe ends with the 0 index
* position representing the output of the pipe (the place you want
* read your data from), and 1 index position representing the
* input file descriptor of the pipe (the place you want to write
* your data).
*/
int pipeEnds_arr1[2];
char str1[] = "Hello, we are feeding this into the pipe that we are through stdout into a pipe and then reading from the pipe and then feeding that output into a file \n"; // make a string array
/* Here we want to actually do the pipe command. We feed it the array
* with the 2 positions in it which will now hold file descriptors
* attached to the current process which allow for input and output
* through the new pipe. At this point, we don't know what the
* exact file decriptors are, but we can look at them by printing
*/
pipe(pipeEnds_arr1);
printf("File Descriptor for pipe ends from array\nPOSITION out 0 : %d\nPOSITION in 1 : %d\n", pipeEnds_arr1[0], pipeEnds_arr1[1]);
/* now my goal is to shift the input of the pipe into the position of
* standard output, so that the print command feeds the pipe, then we
* will try to read from the pipe and redirect the output to the std
* or in this test case out to a file.
*/
int someInt = dup(1); // we moved what was stdout into someInt;
/* put the write end of the pipe in the old stdout position by
* using dup2 so we will print directly into the pipe
*/
dup2(pipeEnds_arr1[1], 1);
/* this is where id like to re-rout the pipe back to stdout but
* im obviously not understanding this correctly
*/
//dup2(someInt, 3);
/* since std out has now been replaced by the pipe write end, this
* printf will print into the pipe
*/
printf("%s", str1);
/* now we read from the pipe into a new string we make */
int n;
char str2[strlen(str1)];
n = read(pipeEnds_arr1[0], str2, sizeof(str2)-1);
str2[n] = 0;
/* open a file and then write into it from the output of the pipe
* that we saved into the str2
*/
int fd = open("tmp.out", O_WRONLY | O_CREAT | O_TRUNC, 0644);
write(fd, str2, strlen(str2));
/* not sure about these last commands and their relevance */
fflush(stdout);
close(pipeEnds_arr1[0]);
close(pipeEnds_arr1[1]);
close(fd);
return 0;
}
最佳答案
管道不在文件描述符之间。它们处于进程之间。所以“通过管道重新设置标准输出”没有任何意义。
您可以做的是修改进程的文件描述符表,使其stdout(fd 1)是管道的写端。您还可以修改另一个进程的文件描述符表,使某些文件描述符(甚至stdin(fd 0))成为同一管道的读取端。它允许您通过两个进程之间的管道传递数据。(如果需要,可以在同一进程中的两个FD之间设置一个管道;它有时很有用,但要注意死锁。)stdout
不是某种魔法实体。它只是fd表中的条目1,它可能指的是任何“文件”,在Unix意义上,它包括常规文件、设备(包括您的shell正在与之通信的控制台和伪终端)、套接字、管道、FIFOs以及操作系统认为值得允许流式访问的任何其他内容。
通常,当shell启动一个正在运行的命令行实用程序时,它首先从自己的fd 0、1和2(stdin、stdout和stderr)克隆fds 0、1和2,它们通常都是相同的设备:控制台,或者现在更常见的是,您正在使用的图形控制台应用程序提供的伪终端。但是可以使用shell重定向操作符、shell管道操作符和一些shell提供的特殊文件来更改这些赋值。
最后,管道在内核中确实有小的缓冲区,但关键是单词“small”--缓冲区可能只有4096字节。如果已满,则尝试写入管道的操作将挂起,直到空间变为可用,只有在从另一个sude读取数据时才会发生这种情况。这就是为什么如果同一个进程同时使用管道的两侧,那么死锁是如此容易:如果进程挂起等待pileto被清空,那么它将无法读取管道。
关于c - 如何使用dup和或dup2将标准重定向到管道中,然后再重定向到另一个管道,然后再回到标准输出中?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39538949/