【发布时间】:2016-09-16 19:35:07
【问题描述】:
好吧,有十亿个与 dup、dup2、fcntl、pipe 和各种在存在多个进程时很棒的东西有关的演示。然而,我还没有看到一件非常基本的事情,我认为这将有助于解释管道的行为及其与标准输出和输入的关系。
我的目标是简单地(在同一过程中)通过管道将标准输出直接重新路由回标准输出。我已经完成了这个 中间阶段将管道输出重定向到文件或写入缓冲区......然后将标准输出放回它开始的位置。那时,我当然可以将缓冲区写回标准输出,但我不想这样做。
由于我将标准输出移动到文件表中的另一个位置,我想将管道的输出直接馈送到新的标准输出位置,并像往常一样打印。
我觉得文件表周围有某种我不理解的层。
#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。
我相信必须有一种方法可以将管道的“读取”或输出端路由到同一个缓冲区,然后再到达外壳。我已经想出了如何将管道输出路由到一个字符串中,然后我可以为所欲为。在下面我发布的示例代码中,我将首先将管道路由到一个字符串,然后打开一个文件并将字符串写入该文件的打开文件描述符......
#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;
}
【问题讨论】:
-
标准输出是总是文件描述符
1。你在someInt中拥有的是一个不同于1调用后的描述符dup2的描述符。dup系统调用确实重复描述符,它不使用引用或链接或类似的东西。此外,dup调用不会修改您传递的描述符编号。在pipe调用之后,pipeEnds_arr1[1]不会随时更改值(描述符编号)。 -
这无论如何都行不通。管道的一端用于写入,另一端用于读取。因此,您可以将
stdout替换为管道的写入端,并且您的程序可以将内容写入管道(认为它正在写入stdout)。但是管道的另一端不能直接连接到原来的stdout。有一段代码需要从管道中读取,并将数据写入原来的stdout。 -
这在理论上也行不通,因为它会创建一个无限循环。想想看 - 你最终会将 stdout 的输出反馈给它自己。
-
@user3386109 std out 以某种方式从 printf 等命令中获取信息,然后将其发送到缓冲区,然后刷新到 shell。必须有一种方法可以将管道的“读取”或输出端路由到同一个缓冲区,然后再到达外壳。 “顺便说一句,一些代码”是什么意思?我已经想出了如何将管道输出路由到一个字符串中,然后我可以随心所欲,但是我的理解中仍然缺少一些东西,因为似乎没有必要将输出路由到其他东西然后发送出去......?应该是一步。
-
@user6840486 我和你在 rici 的回答下交谈的人是同一个人。我正在等待您发布代码,显示您如何“在同一进程中通过管道相当轻松地将我的标准输出路由到文件”。将管道输出路由到字符串的代码也会很有趣。