對於任何一個進程,在啟動時,都會打開三個流:stdin(標準輸入), stdout(標準輸出), stderr(標準錯誤輸出)。Stdout,stderr是process與Display之間,stdin是process與keyboard之間。也就是說系統的標準輸入輸出,是進程與設備間交流的橋梁。 但 ...
對於任何一個進程,在啟動時,都會打開三個流:stdin(標準輸入), stdout(標準輸出), stderr(標準錯誤輸出)。Stdout,stderr是process與Display之間,stdin是process與keyboard之間。也就是說系統的標準輸入輸出,是進程與設備間交流的橋梁。
但是在很多情況下,我們的程式數據並不來自於標準輸入,我們在使用標準輸出時,也不希望寫到顯示器上,可能是文件,網路,印表機等。這時候就需要IO Redirect來作用了。還有,為了方便使用等,我們希望將寫到Stdout的數據作為另外一個進程的輸入,其實這也是IO redirect的一種,不過它有個特殊的名字——pipe。
1、IO Redirect
1.1 File handle (File Description)
操作系統內核會為每一個進程分配很多file handler(也叫 File Description),其中初始時會分配3個handle,用數字0,1,2來表示,分別分配給了stdin, stdout, stderr。其他的則是隨著需要分配的。
這樣一來,就可以直接使用0,1,2來表示Stdio了。
在linux上使用lsof -p pid查看一個進程打開了哪些文件。下麵是一個查看運行中的top命令的情況:
1.2 基本的重定向操作符:>與<
< 將標準輸入(stdin, 0)重定向,也就是說數據來源不是鍵盤,而是其他,例如文件等。
> 將標準輸出(stdout, 1)重定向,也就是說數據不再寫到顯示器,而是其他地方。
其中在 >,< 操作符的左邊,只能是FD,右邊可能是file,也可以是FD等。此外, <等價於 <1, >等價於1>,所以2> 就是將標準錯誤輸出(stderr, 2)重定向。
IO redirect的本質是什麼呢?在我看來本質是FD的賦值。怎麼理解呢?
預設情況下一個,一個進程(例如:ls)是這樣的:
對於一個進程而言: #0 = keyboard #1 = display #2 = display
1.2.1 操作符右邊是文件
ls >a:代表了 fd1=a #0 = keyboard #1 = a #2 = display
Ls 3>a :代表了fd3=a
sort<file.txt :代表了fd0=file.txt
1.2.2 操作符右邊是FD
如果希望在多個FD之間進行賦值運算,那麼就用>&或者<&。
那麼理解上還是 >時賦值運算符,&則是dup2系統調用了。
2>&1的意思就是 對 FD1執行dup2,得到FD1的拷貝,然後賦值給FD2,也就是說FD1指向了誰,FD2也去指向誰。
例如:
3>file.txt 2>&3 代表了:FD3-->file.txt,那麼FD2--->file.txt
需要註意的是:>本身不要求文件必須是存在的,但是經過了上述複製並賦值操作和後,啟動進程之初就要準備好相應的流,此時就需要文件file.txt必須是存在的。
1.3 變體操作符 >>
如果將stdout或者stderr 重定向到一個文件,但文件里已經有內容,會是什麼結果呢?使用 > file時,文件中已有的內容會被truncate掉,也就是文件內容被清除了。
如果想要保留文件內容怎麼辦呢?
有一個變體操作符:>> 以append的方式重定向。
2、Pipe
如果希望將輸出內容,直接作為另外一個程式的輸入,這種技術成為Pipe,能夠進行Pipe的進程,必須是父子進程。用“|” 來表示管道。Pipe也是進程間通信的一種技術。
例如:lsof -p pid | grep xxx ,父進程是 lsof, 子進程是grep。
本篇內容適用於 Windows,Linux,Unix等操作系統。