dup和dup2
最近寫那個 myshell 需要用到多管道 以及重定向方面的知識,實現過程中 其中避不開的一個函數就是我的標題dup 與dup2
它們的作用都是用來複制一個文件的描述符。它們經常用來重定向進程的stdin(0)、stdout(1)和stderr(2)。
函數原型
#include <unistd.h>
int dup( int oldfd );
int dup2( int oldfd, int targetfd );
dup()函數
利用函數dup,我們可以複製一個描述符。傳給該函數一個既有的描述符,它就會返回一個新的描述符,這個新的描述符是傳給它的描述符的拷貝。這意味着,這兩個描述符共享同一個數據結構。
dup2()函數
dup2函數跟dup函數相似,但dup2函數允許調用者規定一個有效描述符和目標描述符的id。dup2函數成功返回時,目標描述符(dup2函數的第二個參數)將變成源描述符(dup2函數的第一個參數)的複製品,換句話說,兩個文件描述符現在都指向同一個文件,並且是函數第一個參數指向的文件。下面我們用一段代碼加以說明:
int oldfd;
oldfd = open("app_log", (O_RDWR | O_CREATE), 0644 );
dup2( oldfd, 1 );
close( oldfd );
這是一段用來演示的代碼
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int pfds[2];
if ( pipe(pfds) == 0 ) {
if ( fork() == 0 ) {
close(1);
dup2( pfds[1], 1 );
close( pfds[0] );
execlp( "ls", "ls", "-l", NULL );
} else {
close(0);
dup2( pfds[0], 0 );
close( pfds[1] );
execlp( "wc", "wc", "-l", NULL );
}
return 0;
}
在示例代碼中,首先在第9行代碼中建立一個管道,然後將應用程序分成兩個進程:一個子進程(第13–16行)和一個父進程(第20–23行)。接下來,在子進程中首先關閉stdout描述符(第13行),然後提供了ls –l命令功能,不過它不是寫到stdout(第13行),而是寫到我們建立的管道的輸出端,這是通過dup2函數來完成重定向的。在第14行,使用dup2 函數把stdout重定向到管道(pfds[1])。之後,馬上關掉管道的輸入端。然後,使用execlp函數把子進程的映像替換爲命令ls –l的進程映像,一旦該命令執行,它的任何輸出都將發給管道的輸入端。
現在來研究一下管道的接收端。從代碼中可以看出,管道的接收端是由父進程來擔當的。首先關閉stdin描述符(第20行),因爲我們不會從機器的鍵盤等標準設備文件來接收數據的輸入,而是從其它程序的輸出中接收數據。然後,再一次用到dup2函數(第21行),讓管道的輸入端作爲輸入,這是通過讓文件描述符0(即常規的stdin)重定向到pfds[0]實現的。關閉管道的stdout端(pfds[1]),因爲在這裏用不到它。最後,使用 execlp函數把父進程的映像替換爲命令wc -l的進程映像,命令wc -l把管道的內容作爲它的輸入(第23行)。
那個多管道確實蠻難寫的有想法寫不出來代碼,好不容易寫出來代碼,卻是個段錯誤!!!
最近確實感覺腦子越來越不夠用了 哎