好的,有十亿个演示与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/

10-16 14:16