dup和dup2也是兩個很實用的調用,它們的做用都是用來複制一個文件的描寫敘述符。數據結構
它們經常常使用來重定向進程的stdin、stdout和stderr。這兩個函數的原形例如如下:app
#include <unistd.h> int dup( int oldfd ); int dup2( int oldfd, int targetfd );
傳給該函數一個既有的描寫敘述符,它就會返回一個新的描寫敘述符,這個新的描寫敘述符是傳給它的描寫敘述符的拷貝。這意味着,這兩個描寫敘述符共享同一個數據結構。好比,假設咱們對一個文件描寫敘述符運行lseek操做,獲得的第一個文件的位置和第二個是同樣的。如下是用來講明dup函數用法的代碼片斷:
函數
int fd1, fd2; ... fd2 = dup( fd1 );
dup2()函數:
dup2函數跟dup函數類似,但dup2函數贊成調用者規定一個有效描寫敘述符和目標描寫敘述符的id。dup2函數成功返回時,目標描寫敘述符(dup2函數的第二個參數)將變成源描寫敘述符(dup2函數的第一個參數)的複製品,換句話說,兩個文件描寫敘述符現在都指向同一個文件,並且是函數第一個參數指向的文件。如下咱們用一段代碼加以說明:
spa
int oldfd; oldfd = open("app_log", (O_RDWR | O_CREATE), 0644 ); dup2( oldfd, 1 ); close( oldfd );
如下咱們介紹一個更加深刻的演示樣例代碼。回顧一下命令行管道,咱們可以將ls –l命令的標準輸出做爲標準輸入鏈接到wc –l命令。接下來。咱們就用一個C程序來加以說明這個過程的實現。代碼例如如下所看到的。命令行
#include <stdio.h> #include <stdlib.h> #include <unistd.h> int main() { int pfds[2]; 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; }
以後,當即關掉管道的輸入端。而後,使用execlp函數把子進程的映像替換爲命令ls –l的進程映像,一旦該命令運行,它的不論什麼輸出都將發給管道的輸入端。
現在來研究一下管道的接收端。從代碼中可以看出,管道的接收端是由父進程來擔當的。首先關閉stdin描寫敘述符,因爲咱們不會從機器的鍵盤等標準設備文件來接收數據的輸入,而是從其餘程序的輸出中接收數據。code
而後,再一次用到dup2函數。讓管道的輸入端做爲輸入,這是經過讓文件描寫敘述符0(即常規的stdin)重定向到pfds[0]實現的。關閉管道的stdout端(pfds[1]),因爲在這裏用不到它。最後,使用 execlp函數把父進程的映像替換爲命令wc -l的進程映像,命令wc -l把管道的內容做爲它的輸入。blog