1. 程式人生 > >[linux]--使用dup和dup2重定向和還原

[linux]--使用dup和dup2重定向和還原

       源於開發一個應用將資料寫的裝置節點中,但是裝置節點具有可變性,所以不在寫死,而是先確定好,開啟fd再將內容寫進去,最終寫入fd中的是一個開源程式,沒有辦法傳遞fd,不過它會把它要輸出的東西輸出到stdout中,開啟這個開源程式之前把stdout重定向到fd上就可以完成了對接。鋪墊完了,下面就開始正題。

      其實這個APUE上有講這個兩個函式,但是說的太標準了的書面語,也沒有給例子,就沒有辦法快速理解和使用了。看到一個10年前的好貼《使用dup2重定向了標準輸出後,使用什麼方法恢復對終端的輸出??》解決了問題。完整程式碼如下:

[cpp] view plain copy
print?
  1. #include <stdio.h>;
  2. #include <unistd.h>;
  3. #include <stdlib.h>;
  4. #include <fcntl.h>;
  5. #include <sys/types.h>;
  6. #include <sys/stat.h>;
  7. #include <string.h>;
  8. #include <strings.h>;
  9. int main()  
  10. {  
  11.         int sfd = dup(STDOUT_FILENO), testfd;  
  12.         printf("sfd = [%d]\n"
    , sfd);  
  13.         testfd = open("./temp",O_CREAT | O_RDWR | O_APPEND);  
  14.         if (-1 == testfd)  
  15.         {  
  16.                 printf("open file error.\n");  
  17.                 exit(1);  
  18.         }  
  19.         /* 重定向 */
  20.         if (-1 == dup2(testfd,STDOUT_FILENO) ) {  
  21.                 printf("can't redirect fd error\n"
    );  
  22.                 exit(1);  
  23.         }  
  24.         /* 此時向stdout寫入應該輸出到檔案 */
  25.         write(STDOUT_FILENO,"file\n",5);  
  26.         /* 恢復stdout */
  27.         if (-1 != dup2(sfd,STDOUT_FILENO) ) {  
  28.                 printf("recover fd ok \n");  
  29.                 /* 恢復後,寫入stdout應該向螢幕輸出 */
  30.                 write(STDOUT_FILENO,"stdout\n",7);  
  31.         }  
  32.         printf("gogogogogogo!\n");  
  33.         close(testfd);  
  34. }  
#include <stdio.h>;
#include <unistd.h>;
#include <stdlib.h>;
#include <fcntl.h>;
#include <sys/types.h>;
#include <sys/stat.h>;
#include <string.h>;
#include <strings.h>;

int main()
{
        int sfd = dup(STDOUT_FILENO), testfd;

        printf("sfd = [%d]\n", sfd);

        testfd = open("./temp",O_CREAT | O_RDWR | O_APPEND);
        if (-1 == testfd)
        {
                printf("open file error.\n");
                exit(1);
        }

        /* 重定向 */
        if (-1 == dup2(testfd,STDOUT_FILENO) ) {
                printf("can't redirect fd error\n");
                exit(1);
        }

        /* 此時向stdout寫入應該輸出到檔案 */
        write(STDOUT_FILENO,"file\n",5);

        /* 恢復stdout */
        if (-1 != dup2(sfd,STDOUT_FILENO) ) {
                printf("recover fd ok \n");

                /* 恢復後,寫入stdout應該向螢幕輸出 */
                write(STDOUT_FILENO,"stdout\n",7);
        }

        printf("gogogogogogo!\n");
        close(testfd);
}

     總結:重定向好似抗戰片中的將鐵軌移到別的路上,或者走向深谷/dev/null,或者走向想讓其走的地方fd。再說下,一開始以為我還以為dup2(STDOUT_FILENO, STDOUT_FILENO);就恢復了呢,結果關閉fd時候,顯示關閉成功,但是裝置卻再也打不開了,因為我並沒有真正還原。


另外:這裡給出一些乾貨以明確理解。

一般在教材中不會明確區分,但是我們應注意到標準輸入有兩層含義:一是指STDIN_FILENO(慣例指定的標準輸入裝置描述符);另一層含義則是指標準輸入裝置(如鍵盤)。同樣,標準輸出也有兩層含義:一是指STDOUT_FILENO(慣例指定的標準輸出裝置描述符);另一層含義則是指標準輸出裝置(如顯示器)。    scanf函式從標準輸入讀取內容,我們通常會認為是從鍵盤讀取的。PRintf函式把內容輸出到標準輸出,我們通常認為是輸出到顯示器上。這並沒有問題,但前提是“在通常情況下”。    精確地說,scanf函式是從檔案描述符STDIN_FILENO(0)所關聯的檔案中讀取,而prinf函式則是輸出到檔案描述符STDOUT_FILENO(1)所關聯的檔案中。    如果STDIN_FILENO關聯的檔案不是鍵盤,那麼scanf就不會從鍵盤讀取內容,同理,如果STDOUT_FILENO關聯的檔案不是顯示器,那麼printf也不會將內容輸出到顯示器。