1. 程式人生 > >Linux IO 重定向自己的理解

Linux IO 重定向自己的理解

內容比較簡潔和高效

1:字串在shell中的三種表達形式:

單引號‘this is’;雙引號“”;什麼都不加。在‘’中,原樣輸出,轉義字元和變數都是無效的;而“”中可以保持轉移字元和變數的含義;什麼都不加的做法和“”是同樣的。所以shell中什麼都不加的也是字串,這就和其他程式語言有很大的區別,但是shell本身就是命令列中各種命令的集合,仔細想想這種做法也是符合通常情況下命令列的做法的,命令列中也沒有加‘’或者“”。

2:IO重定向

1>&2和2>&1的區別是什麼?>和>&的區別?<和<&的區別?
2-1:>和>&的區別
似乎終於有點頭目了>後面一般跟著的是filename檔名,而>&後面一般跟著的是FD,檔案描述符,是一個檔案描述符數字。同理也是<和<&的區別。因為>其實是隱含的1>,而當>&前面不指定FD時候,是1>&。對<而言,隱含的是0<;同理<&是隱含的0<&。
所以別人家的總結不是隨便說說的:

COMMAND_OUTPUT >
   # 將stdout重定向到一個檔案.
   # 如果這個檔案不存在, 那就建立, 否則就覆蓋.

ls -lR > dir-tree.list
   # 建立一個包含目錄樹列表的檔案.

: > filename
   # >操作, 將會把檔案"filename"變為一個空檔案(就是size為0).
   # 如果檔案不存在, 那麼就建立一個0長度的檔案(與'touch'的效果相同).
   # :是一個佔位符, 不產生任何輸出.

> filename
   # >操作, 將會把檔案"filename"變為一個空檔案(就是size為0
). # 如果檔案不存在, 那麼就建立一個0長度的檔案(與'touch'的效果相同). # (與上邊的": >"效果相同, 但是某些shell可能不支援這種形式.) COMMAND_OUTPUT >> # 將stdout重定向到一個檔案. # 如果檔案不存在, 那麼就建立它, 如果存在, 那麼就追加到檔案後邊. # 單行重定向命令(只會影響它們所在的行): # -------------------------------------------------------------------- 1>filename # 重定向stdout到檔案"filename"
. 1>>filename # 重定向並追加stdout到檔案"filename". 2>filename # 重定向stderr到檔案"filename". 2>>filename # 重定向並追加stderr到檔案"filename". &>filename # 將stdout和stderr都重定向到檔案"filename". M>N **///這裡就十分清楚的表明了這種形式下N為檔名** # "M"是一個檔案描述符, 如果沒有明確指定的話預設為1. # "N"是一個檔名. # 檔案描述符"M"被重定向到檔案"N". M>&N**///這裡就十分清楚的表明了這種形式下N為檔案描述符** # "M"是一個檔案描述符, 如果沒有明確指定的話預設為1. # "N"是另一個檔案描述符.

IO重定向基本原理:http://www.cnblogs.com/weidagang2046/p/io-redirection.html
在linux中會為每一個程序維護一個檔案描述表,可以在/proc/pidNum/fd中檢視,fd通常為數字0~9。
檔案描述符的形式為:
這裡寫圖片描述
因此在實現IO重定向的時候,其實本質最主要的是改變檔案描述表中的0,1,2,,,9這些fd對應專案的內容。例如:

cat > file1.txt

其實是將cat程序中檔案描述表中的fd為1的專案中的內容指定為file1.txt.

exec 6>&2

其實就是將檔案描述表中fd=2的專案對應的內容複製到fd=6的專案所對應的內容。所以>&命令有一個”複製”的含義在裡面,而>命令只是單純的含有”賦值”的含義在裡面。
好像終於有點理解複雜的IO重定向了。

exec 6>&2 2>ver
command >>dev/null &
exec 2>&6 # 恢復 FD2

這個程式碼片段的含義為:先將fd=2裡面的內容複製到fd=6的地方,然後在修改fd=2的內容為ver,這樣命令執行時的標準錯誤(2)就會被重定向到ver,在命令執行之後,再次執行exec 2>&6,將fd=6裡面的內容重新複製回fd=2的地方,這樣就將標準錯誤(2)進行了恢復。

>&n 使用系統呼叫 dup (2) 複製檔案描述符 n 並把結果用作標準輸出
<&n 標準輸入複製自檔案描述符 n <&- 關閉標準輸入(鍵盤) >&- 關閉標準輸出
n<&- 表示將 n 號輸入關閉 n>&- 表示將 n 號輸出關閉
上述所有形式都可以前導一個數字,此時建立的檔案描述符由這個數字指定而不是預設的 0 或 1。如:
2>&1

The general form of this one is M>&N, where "M" & "N" are file descriptor numbers. It combines the output of file descriptors "M" and "N" into a single stream.
[j]<>filename
   # 為了讀寫"filename", 把檔案"filename"開啟, 並且將檔案描述符"j"分配給它.
   # 如果檔案"filename"不存在, 那麼就建立它.
   # 如果檔案描述符"j"沒指定, 那預設是fd 0, stdin.
   #
   # 這種應用通常是為了寫到一個檔案中指定的地方.
   echo 1234567890 > File    # 寫字串到"File".
   exec 3<> File             # 開啟"File"並且將fd 3分配給它.
   read -n 4 <&3             # 只讀取4個字元.
   echo -n . >&3             # 寫一個小數點.
   exec 3>&-                 # 關閉fd 3.
   cat File                  # ==> 1234.67890

在這個例子中,將檔案描述符FD3與檔案File進行了繫結,在read命令中,read程式執行時,其輸入正常為stdin,而為了用檔案描述符FD3進行重定向,所以使用<&3這樣其實也是0<&3,就將Stdin進行了重定向,從而可以從File檔案中進行read,同理在輸出的時候使用>&3(其實也是隱含的1>&3)這樣就將輸出重定向到檔案File中。最後利用exec 3>&-將檔案描述符FD3關閉。

其實仔細想想:

之前就已經說過檔案描述符相當於一個指標,那麼單純的指標在某些場合下是不能直接使用的因此>或<後面可以直接接檔名filename,而當我們想要使用檔案描述符FD的時候,我們就需要使用<&和>&命令。比如:
2>&1:在這條語句中1,2都是檔案描述符,也即我們可以把兩者看作是兩個指標,為了進行重定向(我們想要:輸入到2的資料都重定向至1中),我們將指標1指向的檔案寫入到指標2的對應專案中,&1其實也就可以看作指標1指向的內容,把此內容取出來賦值給指標2的內容。不知道這樣想對不對,但是這和C語言的指標真的是好相像,也是我一整天沒有徹底理解重定向的歸因所在,如果這樣解釋的話就感覺清楚很多了。