linux重定向標準輸入後,再從新打開標準輸入爲何會失效?

首先來看一段代碼:node

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    int fd1,fd2;
    
    fd2 = open("p1.py",O_RDONLY,0);
    dup2(fd2,0);
    char c;
    while( read(0,&c,1) > 0)
        printf("%c",c);
    close(fd2);

    fd1 = open("/dev/stdin",O_RDONLY);

    printf("%d\n",fd1);
    while( read(fd1, &c, 1) > 0)
        printf("%c",c);

    return 0;
}

先講一下文件描述符是什麼。
linux進程每打開一個文件都會返回一個文件描述符(整數)。
這個描述符實際是打開的文件在該進程的描述符表上的偏移值。
好比說p是描述符表,1是描述符,那麼p[1]就可以索引到1描述符對應的打開文件。
有了這個偏移值(文件描述符)就可以快速的找到並操做文件。linux

(固然實際的狀況是這個文件描述符可以索引到打開文件表表項,而後再經過打開文件表表項索引到對應的V-node節點表表項,而這個v-node節點表表項才表明真正的文件。不過只從邏輯上來看不須要理解這個括號裏的說明。)函數

解釋一下這段程序:
一、首先打開了一個叫作p1.py的文件。
二、而後用dup2這個函數使得文件描述符0這個位置的指針指向文件描述符fd2這個位置的指針指向的文件。
也就是說原本是這樣:p[0] = &fiel1,p[fd2] = &file2,如今p[0] = p[fd2] = &file2。
而咱們都知道文件描述符0這個位置對應的文件file1是標準輸入文件/dev/stdin。
那麼這個函數的意義就是把標準輸入重定向到了p1.py這個文件裏了。指針

以後再用標準輸入好比說scanf(),來讀,那麼都是從p1.py這個文件裏讀了。
三、而後把這個文件裏的東西讀出來並輸出到屏幕上。
四、打開/dev/stdin這個文件,這個文件是標準輸入。
五、把這個文件裏的東西讀出來並打印到屏幕上。code

預期結果是什麼?
執行到第5步應該停下來,等待鍵盤輸入。
而後把輸入的東西打印到屏幕。索引

實際結果?
沒有等待鍵盤輸入,它直接把p1.py的文件內容輸出到屏幕上,也就是說和上面的輸出是同樣的!!!進程

why???how???
我打開了一個文件,應該讀取文件裏的內容。而這個文件是標準輸入,那麼既然是標準輸入(從鍵盤輸入),我還沒輸入呢,怎麼就輸出結果了呢???並且結果還很奇特。。。string

這是由於,標準輸入這個文件/dev/stdin是個連接文件!!!
存放的是別的文件的地址!!!
若是文件描述符指向的文件是個普通文件,那麼把這個文件描述符指向別的文件,就是真的指向了別的文件。
而這裏的文件描述符指向的是個連接文件,那麼把這個文件描述符指向別的文件,意味着什麼???意味着它
把這個連接文件裏的內容(地址)更改了,而它仍然指向這個文件。只不過它知道這是個連接文件,所以它會訪問的是這個連接文件中的地址對應的文件。io

理解了上面的操做就能夠說得通了,dup2對於連接文件只是修改了文件中的地址,它並無真正指向別的文件,這也致使了一個問題,那就是它把這個連接文件給修改了,若是進程再次打開這個連接文件,那麼連接文件以前存的地址就沒有了,所以執行file

fd1 = open("/dev/stdin",O_RDONLY);

這個的時候,其實是又一次打開了p1.py這個文件!!!由於/dev/stdin這個文件裏存放的地址已是p1.py這個文件的地址了。。。

相關文章
相關標籤/搜索