bash指南之重定向
Before a command is executed, its input and output may beredirectedusing a special notation interpreted by the shell. Redirection allows commands’ file handles to be duplicated, opened, closed, made to refer to different files, and can change the files the command reads from and writes to. Redirection may also be used to modify file handles in the current shell execution environment. The following redirection operators may precede or appear anywhere within a simple command or may follow a command. Redirections are processed in the order they appear, from left to right.
在一條命令被執行之前,可以使用由shell解釋的特殊符號對其輸入和輸出進行重定向。重定向允許對命令的檔案控制代碼進行復制、開啟、關閉,使其引用不同的檔案,並可以更改命令讀寫的檔案。重定向還可以用於修改當前shell執行環境中的檔案控制代碼。以下重定向操作符可以出現在簡單命令的前面,或中間的任意位置,也可以出現在命令的後面。重定向按照出現順序從左到右被處理。
重定向符可以出現在簡單命令的前中後,也就是說以下示例的結果是一致的,都是把/etc目錄下的檔案列表輸出到all-in-etc檔案。ls命令的執行結果原本應該被輸出到標準輸出上。而這裡利用了>word形式將其重定向到all-in-etc檔案。“>
>all-in-etc ls /etc/ ls >all-in-etc /etc/ ls /etc/ >all-in-etc
重定向在命令列中出現的先後順序相當重要,在命令列中靠左的重定向先於靠右的被處理,所以重定向出現的左右位置差異將導致表現的差異。
ls -l a b c >ls-result 2>&1ls -l a b c 2>&1 >ls-result
上面2條命令中,檔案描述符1代表標準輸出,檔案描述符2代表標準錯誤輸出。
日常使用中,1和2都指向我們使用的模擬終端,不瞭解內情的時候,很容易忽略兩者的差別。可以將兩者分別重定向到不同的檔案,然後執行一條既有正常輸出,又有錯誤輸出的命令,即可觀察出兩者的區別。假設當前目錄下有檔案a和b,不存在檔案c,請執行如下命令:
ls -l a b c >normal-result 2>error-result
該命令的正常輸出將被重定向到normal-result檔案,而錯誤輸出會被重定向到error-result檔案。開啟error-result檔案,會發現其內容為ls提示的“c檔案不存在”的錯誤資訊。也可以刪除這2個重定向中的任一個,只要1和2指向不同的檔案,能驗證標準輸出和標準錯誤輸出都存在且有不同即可。大家可以執行一下如下命令,看一看標準輸入,標準輸出和標準錯誤輸出到底是什麼。
ls -l /proc/$$/fd/
實際上,標準輸入,標準輸出和標準錯誤輸出也被作業系統虛擬成檔案了。
我們可以做如下的實驗:
在當前終端下執行
echo $$
將顯示出當前終端程序的程序id。記下這個數字,然後新開一個模擬終端,在新開的終端中,我們執行如下命令,觀察發生了什麼。
echo "這是來自另一個終端的文字,能看到嗎?" >/proc/2399/fd/1
請把2399換成上一條命令顯示的程序id。
現在應該對這些令人頭暈的所謂標準輸出,標準輸入,檔案描述符,重定向等等概念有了實在的認識了吧?
說簡單點,檔案描述符就是為了方便使用檔案而規定的用來標識檔案流的一個整數,單單有檔案描述符是沒用的,它只是一個名字,一個程式碼,它代表的檔案流才是可用的起作用的東西。0,1和2這三個檔案描述符之所以比較特殊,之所以被稱為標準,也是因為規定,預設情況下,作業系統會替一個程序開啟三個檔案流,給它們分別綁上0,1和2,這就是標準輸入,標準輸出和標準錯誤輸出的實質。我們利用的模擬終端的本質就是一個程序,因此也有這三個數字和相應的檔案流,這些檔案流不就被模擬在/proc/中了嗎?因此,我們這裡討論的重定向,就是利用bash這個shell提供的操作符去控制一個程序開啟的檔案描述符和它們對應的檔案流,這裡的控制怎麼解釋呢?其實就是看bash為我們提供了多少重定向的形式,為我們的控制提供了多少支援。比如重定向標準輸出>normal-result,不就是改變檔案描述符1,使它繫結到一個新的檔案流嗎?"echo '這是來自另一個終端的文字,能看到嗎?' >/proc/2399/fd/1"不就是把echo的標準輸出繫結到/proc/2399/fd/1這個檔案流嗎?不就導致另一個模擬終端的介面上突然顯示一串文字嗎?接下來我們要講解"2>&1",bash提供了這一形式的重定向操作符,其操作的實質就是讓檔案描述符2複製檔案描述符1,結果就是標準輸出和標準錯誤輸出都指向同一個檔案。
讓我們回到上面的那兩條命令,繼續說明重定向的順序問題,看一看“>ls-result 2>&1”和“2>&1>ls-result”有什麼差異。
先說“>ls-result2>&1”,“>ls-result”是把標準輸出重定向到ls-result檔案,這裡代表標準輸出的檔案描述符1可以被省略。“2>&1”在後面會被詳細的說明,其操作上文也已簡單提到,是將檔案描述符2同樣繫結到檔案描述符1代表的檔案流。由於重定向按照出現順序從左到右被處理,所以標準輸出會先被重定向到ls-result檔案,然後,標準錯誤輸出會複製標準輸出,也就是說,標準錯誤輸出也會繫結到ls-result檔案。
“2>&1 >ls-result”的表現則不同,由於標準輸出1和標準錯誤輸出2預設情況下都指向我們使用的模擬終端,因此先執行“2>&1”並不會發生什麼實質性的變化,1和2還是指向終端介面,接著執行“>ls-result”會把標準輸出重定向到ls-result檔案。
因此,要十分注意重定向的出現順序,設定不當的話,將得不到想要的重定向效果。