對於內核而言,所有打開的文件都是通過文件描述符引用。文件描述符是一個非負整數,當進程打開或創建一個文件時,內核向進程返回一個文件描述符。當讀寫文件時,文件描述作為一個標志,標識該文件(如系統調用read和write函數)。
UNIX系統shell把文件描述符0與進程的標准輸入相關聯,把文件描述符1與進程的標准輸出相關聯,把文件描述符2與進程的標准錯誤關聯。這些描述符被宏定義為符號常量。在/usr/include/unistd.h中可以查找到宏定義,如下:
/* Standard file descriptors. */ #define STDIN_FILENO 0 /* Standard input. */ #define STDOUT_FILENO 1 /* Standard output. */ #define STDERR_FILENO 2 /* Standard error output. */有時候我們也許會看STDIN,STDOUT,STDERR。這些和上述所說的引用相同,但這些是由C標准庫stdio.h提供的,而上述的是系統調用函數庫unistd.h提供的。一般Linux命令行的輸入輸出(就是鍵盤輸入,終端顯示)是由系統調用實現的。
數據流重定向是將某個命令執行後,將結果顯示在屏幕的數據傳輸到其他地方,將由鍵盤輸入的數據,替代為從某個文件讀入數據。
執行一個命令,通常它是按如下方式進行:
當執行一個命令時,命令從文件有標准輸入讀取,經過處理,若命令執行所回傳正確的信息,由標准輸出顯示到終端。若命令執行失敗,回傳的錯誤信息由標准錯誤輸出到終端。
Standard Output,Standard Error我們不能將錯誤和正確的信息都傳送到屏幕,因此采用數據流輸出重定向功能,可以將標准輸出,標准錯誤分別傳送到不同的文件和設備中。重定向采用的符號如下:
1、 標准輸入(STDIN_FILENO) 使用<或<< ;
2、 標准輸出(STDOUT_FILENO) 使用>或>>(1>或1>>) ;
3、 標准錯誤(STDERR_FILENO) 使用2>或2>> ;
注:上面提到,0與標准輸入關聯,1與標准輸出關聯,2與標准錯誤關聯。使用>或>>,1>或1>> 表示標准輸出重定向。
列出當前桌面所有文件
kernel@Ubuntu:~/Desktop$ ls C++ UNIX請留意現在桌面文件
將輸出的信息重定向到一個當前不存在的文件夾中
kernel@Ubuntu:~/Desktop$ ls > file kernel@Ubuntu:~/Desktop$現在終端什麼也沒有輸出,因為已經將本來應該顯示到屏幕的數據重定向到file文件中。查看剛才將數據重定向的文件內容
kernel@Ubuntu:~/Desktop$ cat file C++ file為什麼會多出一個剛才重定向的文件?若重定向的文件(本例為file)不存在,系統會自動創建該文件。所以將ls執行後所輸出的數據就多了file這個文件。
再一次向file文件重定向一個不同於上次的數據,結果會如何?
kernel@Ubuntu:~/Desktop$ ll C++/ > file kernel@Ubuntu:~/Desktop$ cat file 總用量 36 drwxrwxr-x 3 kernel kernel 4096 4月 14 13:39 ./ drwxr-xr-x 5 kernel kernel 4096 5月 19 21:16 ../ -rw-rw-r-- 1 kernel kernel 0 4月 12 20:10 Client.cpp -rw-r--r-- 1 kernel kernel 12288 4月 14 13:41 .Client.cpp.swp drwxrwxr-x 2 kernel kernel 4096 5月 8 23:58 HTTP/ -rw-r--r-- 1 kernel kernel 12288 4月 12 17:51 .server.cpp.swpFile文件的內容被第二次重定向的數據給覆蓋,所以> 或1> 下一次的數據會覆蓋原先的數據。如果想要數據只是疊加而不是覆蓋原先數據,使用>> 或 1>> 。
剛才的處理只是將正確的數據重定向到文件,如果出現錯誤,依舊會顯示在終端。因此可以將標准輸出與標准錯誤分別重定向到兩個不同的文件。
kernel@Ubuntu:~/Desktop$ find /home -name .bashrc /home/kernel/.bashrc find: `/home/kernel/.gvfs': 權限不夠 find: `/home/kernel/.cache/dconf': 權限不夠 /home/kernel/Desktop/.bashrc現在把上面出現的正確數據與錯誤數據重定向到兩個文件。
kernel@Ubuntu:~/Desktop$ find /home -name .bashrc > list_right 2> list_error kernel@Ubuntu:~/Desktop$ cat list_right /home/kernel/.bashrc /home/kernel/Desktop/.bashrc kernel@Ubuntu:~/Desktop$ cat list_error find: `/home/kernel/.gvfs': 權限不夠 find: `/home/kernel/.cache/dconf': 權限不夠
現在兩個文件分別存儲了正確和錯誤的數據。
我的理解是這樣的:可以把標准輸出和標准錯誤當作兩條輸出數據的管道(我理解的標准錯誤其實也可以當作標准輸出,不過它輸出的是錯誤信息)。兩條管道在沒有重定向之前是在命令執行完成之後,將管道的數據默認傳送到終端。在重定向後,相當於把管道輸出的端口指向文件或其他設備。
如果要把標准輸出與標准錯誤重定向一個文件,是不是可以按照上面的做法來實現呢?
kernel@Ubuntu:~/Desktop$ find /home -name .bashrc > list 2> list kernel@Ubuntu:~/Desktop$ cat list find: `/home/kernel/./home/kernel/Desktop/.bashrc ome/kernel/.cache/dconf': 權限不夠結果只有標准出錯。那是不是就意味著標准輸入和標准輸出同時進行覆蓋重定向的時候,只有標准出錯? 答案是否定的。因為兩個輸出同時重定向一個文件很類似於fork()函數生成的子進程與父進程之間執行的競爭關系,所以重定向之後文件的數據是很不確定的,兩條數據交叉寫入文件時,可能造成次序混亂。因此可以采用以下方法:
kernel@Ubuntu:~/Desktop$ find /home -name .bashrc >list 2>&1 kernel@Ubuntu:~/Desktop$ cat list /home/kernel/.bashrc find: `/home/kernel/.gvfs': 權限不夠 find: `/home/kernel/.cache/dconf': 權限不夠 /home/kernel/Desktop/.bashrc
這個可以這樣理解,現在有標准輸出和標准錯誤兩條管道,現在將標准錯誤的管道插到標准輸出的管道中,現在標准輸出的管道中就有標准輸出和標准錯誤的數據。2>&1就表示將標准錯誤的數據重定向到標准輸出。
注:一定要注意&這個符號,如果沒有加上這個符號,2>1就表示標准錯誤重定向到文件名為1的文件中,而不是重定向到標准輸出。
Standard Input標准輸入一般是指由鍵盤輸入(STDIN_FILENO),將輸入的數據寫入到指定的文件。
cat命令是直接查看文件內容(當前用戶可讀的前提下)。若後面不加參數,將從鍵盤接受數據。
kernel@Ubuntu:~/Desktop$ cat testing testing # [ctrl]+d退出輸入的數據,直接顯示在當前終端下,利用標准輸出重定向,將輸入的數據寫到文件。
kernel@Ubuntu:~/Desktop$ cat > catfile testing cat file test # [ctrl]+d退出
kernel@Ubuntu:~/Desktop$ cat catfile testing cat file test
現在應該大致理解了鍵盤輸入是怎麼一回事了吧。接下來,將鍵盤輸入重定向到讀取某個文件的內容。這次讀取上一次的list文件。
kernel@Ubuntu:~/Desktop$ cat > catfile < list kernel@Ubuntu:~/Desktop$ cat catfile /home/kernel/.bashrc find: `/home/kernel/.gvfs': 權限不夠 find: `/home/kernel/.cache/dconf': 權限不夠 /home/kernel/Desktop/.bashrc再查看下兩個文件的信息
kernel@Ubuntu:~/Desktop$ ll list catfile -rw-rw-r-- 1 kernel kernel 139 5月 19 23:39 catfile -rw-rw-r-- 1 kernel kernel 139 5月 19 23:21 list如果對這個cat > catfile < list 不好理解,可以這樣去想:可以把cat > catfile當作一個整體,catfile文件本來要接受來自鍵盤的輸入,可是現在將標准輸入的管道重定向到一個文件,於是標准輸入就去讀取list文件的內容並將list文件的內容經標准輸出重定向到catfile文件。於是就可以理解cat catfile 與 cat < catfile的區別了。前面所說cat不加參數是等待鍵盤輸入,那現在給它重定向到一個文件,去讀取文件的內容並顯示。而cat
catfile是直接去顯示文件內容,沒有經過重定向。
標准輸出與標准錯誤的 >> 是向重定向的文件尾繼續添加數據。那標准輸入也是如此嗎?
kernel@Ubuntu:~/Desktop$ cat > catfile <<"EOF" > testing > stop > EOF可以利用<<右側的控制字符,終止輸入,而不需要[ctrl]+d來退出,並且文件的內容也改變了,並沒有疊加的作用。
kernel@Ubuntu:~/Desktop$ cat catfile testing stop總結:
使用重定向可以將屏幕輸出的一些重要的信息保存到文件。如果後台有程序執行並且有相應的輸出,可以將輸出重定向到文件,以避免干擾屏幕的正常輸出。
在剛開始對重定向不好理解的時候,可以將其看作管道,不是真的那個管道命令。可以方便理解和使用重定向。現在所說的輸入輸出都是系統調用來完成的,是直接對內核進行操作,用來完成對磁盤的讀,寫操作。