歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux技術 >> 數據流重定向

數據流重定向

日期:2017/3/3 12:34:59   编辑:Linux技術

對於內核而言,所有打開的文件都是通過文件描述符引用。文件描述符是一個非負整數,當進程打開或創建一個文件時,內核向進程返回一個文件描述符。當讀寫文件時,文件描述作為一個標志,標識該文件(如系統調用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.swp
File文件的內容被第二次重定向的數據給覆蓋,所以> 或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
總結:

使用重定向可以將屏幕輸出的一些重要的信息保存到文件。如果後台有程序執行並且有相應的輸出,可以將輸出重定向到文件,以避免干擾屏幕的正常輸出。

在剛開始對重定向不好理解的時候,可以將其看作管道,不是真的那個管道命令。可以方便理解和使用重定向。現在所說的輸入輸出都是系統調用來完成的,是直接對內核進行操作,用來完成對磁盤的讀,寫操作。

Copyright © Linux教程網 All Rights Reserved