2016-09-16 67 views
0

好吧,有十億個演示涉及到dup,dup2,fcntl,管道和各種各樣的東西,當多個進程存在時都很棒。然而,我還沒有看到一個非常基本的東西,我認爲這將有助於解釋管道的行爲及其與標準輸出和輸入的關係。如何使用dup和/或dup2將標準重定向到管道,然後輸出到antoher管道然後返回標準輸出?

我的目標是簡單地(在相同的過程中)通過直接回到標準輸出。我已經完成了這個 的中間階段,它將管道輸出重定向到一個文件或寫入緩衝區......然後將標準輸出回到它開始的位置。在那一點上,我當然可以將緩衝區寫回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; 
} 

編輯********* OK,我知道那是什麼莫名其妙的std出需要的信息從如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; 
} 
+0

標準輸出是* always *文件描述符'1'。 'someInt'中的描述符與'dup2'調用後的描述符'1'不同。 'dup'系統調用*重複*描述符,它不使用引用或鏈接或類似的東西。另外,'dup'調用不會修改您傳遞的描述符號碼。 'pipeEnds_arr1 [1]'不會在'pipe'調用之後改變值(描述符號)。 –

+1

這在任何情況下都無法工作。管的一端用於書寫,另一端用於書寫。所以你可以用管道的寫入端來替換'stdout',並且你的程序可以在管道中寫入東西(認爲它寫入'stdout')。但是管道的另一端不能直接連接到原來的'stdout'。某些代碼需要從管道中讀取並將數據寫入原始的「stdout」。 – user3386109

+1

即使在理論上這也不行,因爲它會造成無限循環。考慮一下 - 你最終會將stdout的輸出回饋給自己。 – kfx

回答

2

管道不間文件描述符。他們在進程之間。因此,「通過管道重新劃分標準」沒有任何意義。

你可以做的是修改一個進程的文件描述符表,以便其stdout(fd 1)是管道的寫入端。您可以修改另一個進程的文件描述符表,以便某個文件描述符,甚至stdin(fd 0)是同一管道的讀取端。這允許您通過兩個進程之間的管道傳遞數據。 (如果你願意,你可以在同一個過程中在兩個fds之間建立一個管道,但它有時候會很有用,但要小心死鎖。)

stdout不是某種神奇的實體。它只是fd表中的條目1,它可能指任何「文件」,在Unix的意義上,它包括常規文件,設備(包括控制檯和shell與之通信的僞終端),套接字,管道,FIFO和其他任何操作系統認爲值得允許流式訪問。

通常,當shell開始運行命令行工具時,它首先從fd 0,1和2(它們通常是所有的fd 0,1和2)中複製fds 0,1和2(stdin,stdout和stderr)相同的設備:控制檯,或現在更常見的是,您正在使用的圖形控制檯應用程序提供的僞終端。但是您可以使用例如shell重定向操作符,shell管道操作符和一些shell提供的特殊文件來更改這些分配。

最後,管道在內核中確實有小緩衝區,但關鍵字是「小」字 - 緩衝區可能只能容納4096字節。如果已滿,則試圖寫入管道的操作將掛起直到空間變爲可用,這隻有在從另一個sude讀取數據時纔會發生。這就是爲什麼如果相同的過程使用管道的兩端都很容易死鎖:如果進程等待堆棧被清空,它將永遠無法讀取管道。

+0

我不太清楚你爲什麼說管道只能在不同的過程之間。在相同的過程中,我可以很容易地通過管道將標準輸出路由到文件。那麼從標準輸出管道並將其用作緩衝區,然後將輸出管道的輸出端重新導回到標準輸出端呢?我仍然不明白爲什麼這不可能發生。 我相當肯定我正確地將打印語句路由到了管道中,並且由於管道的行爲類似於緩衝區,我應該能夠以某種方式將該緩衝區發送回控制檯? – user6840486

+0

*「在相同的過程中,我可以很容易地通過管道將我的標準輸出路由到文件。」*如果將此代碼添加到問題@ user6840486將有幫助。 – user3386109

+0

對不起,我對此有點新。我應該如何去添加這段代碼?我應該將它作爲編輯發佈還是將其添加到其他地方? @ user3386109 – user6840486