什麼是資料流重導向
什麼是資料流重導向啊?這得要由命令的運行結果談起!一般來說,如果你要運行一個命令,通常他會是這樣的:
圖 5.1.1、命令運行過程的資料轉送情況
我們運行一個命令的時候,這個命令可能會由檔案讀入資料,經過處理之後,再將資料輸出到螢幕上。 在當中, standard output 與 standard error output 分別代表『標準輸出』與『標準錯誤輸出』, 這兩個玩意兒預設都是輸出到螢幕上面來的啊!那麼什麼是標準輸出與標準錯誤輸出呢?
standard output 與 standard error output
簡單的說,標準輸出指的是『命令運行所回傳的正確的資訊』,而標準錯誤輸出可理解為『 命令運行失敗後,所回傳的錯誤資訊』。舉個簡單例子來說,我們的系統預設有 /etc/crontab 但卻無 /etc/vbirdsay, 此時若下達『 cat /etc/crontab /etc/vbirdsay 』這個命令時,cat 會進行:
- 標準輸出:讀取 /etc/crontab 後,將該檔案內容顯示到螢幕上;
- 標準錯誤輸出:因為無法找到 /etc/vbirdsay,因此在螢幕上顯示錯誤資訊
不管正確或錯誤的資料都是預設輸出到螢幕上,所以螢幕當然是亂亂的!那能不能透過某些機制將這兩股資料分開呢? 當然可以啊!那就是資料流重導向的功能啊!資料流重導向可以將 standard output (簡稱 stdout) 與 standard error output (簡稱 stderr) 分別傳送到其他的檔案或裝置去,而分別傳送所用的特殊字元則如下所示:
- 標準輸入 (stdin) :代碼為 0 ,使用 < 或 << ;
- 標準輸出 (stdout):代碼為 1 ,使用 > 或 >> ;
- 標準錯誤輸出(stderr):代碼為 2 ,使用 2> 或 2>> ;
1> :以覆蓋的方法將『正確的資料』輸出到指定的檔案或裝置上;1>>:以累加的方法將『正確的資料』輸出到指定的檔案或裝置上;2> :以覆蓋的方法將『錯誤的資料』輸出到指定的檔案或裝置上;2>>:以累加的方法將『錯誤的資料』輸出到指定的檔案或裝置上;
要注意喔,『 1>> 』以及『 2>> 』中間是沒有空格的!
將 stdout 與 stderr 分存到不同的檔案去
[dmtsai@www ~]$ find /home -name .bashrc > list_right 2> list_error
將錯誤的資料丟棄,螢幕上顯示正確的資料
[dmtsai@www ~]$ find /home -name .bashrc 2> /dev/null/home/dmtsai/.bashrc <==只有 stdout 會顯示到螢幕上, stderr 被丟棄了
將正確與錯誤資料通通寫入同一個檔案去
將命令的資料全部寫入名為 list 的檔案中[dmtsai@www ~]$ find /home -name .bashrc > list 2> list <==錯誤[dmtsai@www ~]$ find /home -name .bashrc > list 2>&1 <==正確[dmtsai@www ~]$ find /home -name .bashrc &> list <==正確
上述表格第一行錯誤的原因是,由於兩股資料同時寫入一個檔案,又沒有使用特殊的文法, 此時兩股資料可能會交叉寫入該檔案內,造成次序的錯亂。所以雖然最終 list 檔案還是會產生,但是裡面的資料排列就會怪怪的,而不是原本螢幕上的輸出排序。 至於寫入同一個檔案的特殊文法如上表所示,你可以使用 2>&1 也可以使用 &> ! 一般來說,鳥哥比較習慣使用 2>&1 的文法啦!
standard input : < 與 <<
瞭解了 stderr 與 stdout 後,那麼那個 < 又是什麼呀?呵呵!以最簡單的說法來說, 那就是『將原本需要由鍵盤輸入的資料,改由檔案內容來取代』的意思。 我們先由底下的 cat 命令操作來瞭解一下什麼叫做『鍵盤輸入』吧!
利用 cat 命令來建立一個檔案的簡單流程[root@www ~]# cat > catfiletestingcat file test<==這裡按下 [ctrl]+d 來離開[root@www ~]# cat catfiletestingcat file test
由於加入 > 在 cat 後,所以那個 catfile 會被主動的建立,而內容就是剛剛鍵盤上面輸入的那兩行資料了。 唔!那我能不能用純文字檔案取代鍵盤的輸入,也就是說,用某個檔案的內容來取代鍵盤的敲擊呢? 可以的!如下所示:
用 stdin 取代鍵盤的輸入以建立新檔案的簡單流程[root@www ~]# cat > catfile < ~/.bashrc[root@www ~]# ll catfile ~/.bashrc-rw-r--r-- 1 root root 194 Sep 26 13:36 /root/.bashrc-rw-r--r-- 1 root root 194 Feb 6 18:29 catfile# 注意看,這兩個檔案的大小會一模一樣!幾乎像是使用 cp 來複製一般!
這東西非常的有協助!尤其是用在類似 mail 這種命令的使用上。 理解 < 之後,再來則是怪可怕一把的 << 這個連續兩個小於的符號了。 他代表的是『結束的輸入字元』的意思!舉例來講:『我要用 cat 直接將輸入的資訊輸出到 catfile 中, 且當由鍵盤輸入 eof 時,該次輸入就結束』,那我可以這樣做:
[root@www ~]# cat > catfile << "eof"> This is a test.> OK now stop> eof <==輸入這關鍵詞,立刻就結束而不需要輸入 [ctrl]+d[root@www ~]# cat catfileThis is a test.OK now stop <==只有這兩行,不會存在關鍵詞那一行!
看到了嗎?利用 << 右側的控制字元,我們可以終止一次輸入, 而不必輸入 [crtl]+d 來結束哩!這對程式寫作很有協助喔!好了,那麼為何要使用命令輸出重導向呢?我們來說一說吧!
管線命令 (pipe)
就如同前面所說的, bash 命令啟動並執行時候有輸出的資料會出現! 那麼如果這群資料必需要經過幾道手續之後才能得到我們所想要的格式,應該如何來配置? 這就牽涉到管線命令的問題了 (pipe) ,管線命令使用的是『 | 』這個界定符號! 另外,管線命令與『連續下達命令』是不一樣的呦! 這點底下我們會再說明。底下我們先舉一個例子來說明一下簡單的管線命令。
假設我們想要知道 /etc/ 底下有多少檔案,那麼可以利用 ls /etc 來查閱,不過, 因為 /etc 底下的檔案太多,導致一口氣就將螢幕塞滿了~不知道前面輸出的內容是啥?此時,我們可以透過 less 命令的協助,利用:
[root@www ~]# ls -al /etc | less
如此一來,使用 ls 命令輸出後的內容,就能夠被 less 讀取,並且利用 less 的功能,我們就能夠前後翻動相關的資訊了!很方便是吧?我們就來瞭解一下這個管線命令『 | 』的用途吧! 其實這個管線命令『 | 』僅能處理經由前面一個命令傳來的正確資訊,也就是 standard output 的資訊,對於 stdandard error 並沒有直接處理的能力。那麼整體的管線命令可以使用表示:
圖 6.1.1、 管線命令的處理
在每個管線後面接的第一個資料必定是『命令』喔!而且這個命令必須要能夠接受 standard input 的資料才行,這樣的命令才可以是為『管線命令』,例如 less, more, head, tail 等都是可以接受 standard input 的管線命令啦。至於例如 ls, cp, mv 等就不是管線命令了!因為 ls, cp, mv 並不會接受來自 stdin 的資料。 也就是說,管線命令主要有兩個比較需要注意的地方:
- 管線命令僅會處理 standard output,對於 standard error output 會予以忽略
- 管線命令必須要能夠接受來自前一個命令的資料成為 standard input 繼續處理才行。
關於減號 - 的用途
管線命令在 bash 的連續的處理常式中是相當重要的!另外,在 log file 的分析當中也是相當重要的一環, 所以請特別留意!另外,在管線命令當中,常常會使用到前一個命令的 stdout 作為這次的 stdin , 某些命令需要用到檔案名稱 (例如 tar) 來進行處理時,該 stdin 與 stdout 可以利用減號 "-" 來替代, 舉例來說:
[root@www ~]# tar -cvf - /home | tar -xvf -
上面這個例子是說:『我將 /home 裡面的檔案給他打包,但打包的資料不是紀錄到檔案,而是傳送到 stdout; 經過管線後,將 tar -cvf - /home 傳送給後面的 tar -xvf - 』。後面的這個 - 則是取用前一個命令的 stdout, 因此,我們就不需要使用 file 了!這是很常見的例子喔!注意注意!
轉自 http://vbird.dic.ksu.edu.tw/linux_basic/0320bash_5.php
http://vbird.dic.ksu.edu.tw/linux_basic/0320bash_6.php#pipe_7