Linux 下強大得不得了的 IO 重定向

在 Linux 下,I/O 重定向可以稱為是命令行最酷的特性了。命令的輸入可以來自於鍵盤或者文件,輸出可以列印在終端模擬器,也可以列印到文件,這裡就需要用到 I/O 的重定向特性,利用 I/O 的重定向功能還可以實現強大的命令管道。你準備好去一探究竟了嗎?

什麼是 I/O 呢?簡單一點,I 是 input,輸入;O 是 output,輸出。

今天我們將學習以下命令,從學習這些命令的使用方法來體會 I/O 重定向的酷炫特性。

  • cat:查看文件內容
  • sort:對文本內容排序
  • uniq:用於報告或忽略文件中的重複行,一般與sort命令結合使用
  • grep:找出匹配的行
  • wc:列印文件中換行符,字,和位元組個數
  • head:輸出文件開頭部分
  • tail:輸出文件結尾部分
  • tee:從標準輸入讀取數據,並同時寫到標準輸出和文件

1. 標準輸入,標準輸出和標準錯誤

標準輸入:程序執行一般需要從標準輸入(stdin)讀取數據,一般標準輸入設備是連接到鍵盤的。 標準輸出:程序執行的過程中會產生結果,結果要顯示出來就需要將結果輸出到標準輸出設備(stdout),一般標準輸出設備連接到顯示器。 標準出錯:程序運行的工程中可能會有一些錯誤提示,這就需要輸出到標準出錯設備(stderr),一般標準出錯設備也是連接到顯示器的。

I/O 重定向允許我們更改輸出地點和輸入來源。一般地,輸出到屏幕,輸入來自鍵盤, 但是通過 I/O 重定向,我們可以做出改變。

2. 標準輸出重定向

標準輸出一般是輸出到屏幕的,但是我們使用 I/O 的重定向功能可以將標準輸出重定向到其他地方,比如一個文件。重定向需要使用 ">" 重定向符號實現。下面是一個例子:

ls -l /usr/bin > ls-output.txt

我們把 ls -l /usr/bin 的結果作為輸入,使用 > 將其重定向到 ls-output.txt 這個文件。好了,這下看看在當前目錄是不是多了一個 ls-output.txt 文件呢?順便使用 less 命令看看裡面的內容是什麼?

不知道大家有沒有注意到,我們單獨輸入 ls 命令的時候會在終端回顯輸出結果,就相當於把輸出列印在屏幕上,但是使用了 > 重定向之後,終端沒有回顯了,而是把輸出內容寫到一個文件去了。再來看一個例子:

ls -l /bin/usr > ls-output.txt

這次我們查看的目錄 /bin/usr 並不存在,所以終端會回顯一行提示信息,這是標準出錯信息,那這時候 ls-output.txt 文件裡面應該是什麼內容呢?是 ls -l /usr/bin > ls-output.txt 的結果嗎?

我們發現 ls-output.txt 文件中沒有內容了,這是為什麼?其實 > 有重寫的特性,我們執行 ls -l /bin/usr > ls-output.txt 的時候重寫了這個文件,而重寫的時候寫入的是空內容,所以導致這個文件裡面的內容沒有了。

噢哦,有點有趣吧,那我們是不是可以使用 > file 來創建一個空文件呢?快去試試吧!

我們現在知道 > 的重寫特性了,那我們既要保存文件中的內容,又要通過重定向的方式向文件中追加內容,那改怎麼辦呢?別著急,和 > 孿生的兄弟 >> 就是專門干這個事情的,大家可以試試將上面兩個例子中的 > 換成 >> 試試,看看效果如何?當然你想看得更清楚一點 >> 的特性,你可以將第二個例子還一下,因為第二個例子是不會向文件寫入新的內容的,ls -l /bin/usr 的輸出為空,我們可以換成一個輸出不為空的,比如:

ls -l /usr/bin >> ls-output.txt ls -l /usr/share/ >> ls-output.txt

執行完第一條命令的時候看看 ls-output.txt 的內容和文件大小,再執行第二條命令,對比一下結果,理解 >>> 的特性。

3. 標準錯誤重定向

標準錯誤重定向沒有專用的重定向操作符。為了重定向標準錯誤,我們必須參考其文件描述符。 一個程序可以在幾個編號的文件流中的任一個上產生輸出。雖然我們已經將這些文件流的前 三個稱作標準輸入、輸出和錯誤,shell 內部分別將其稱為文件描述符 0、1 和 2。shell 使用文件描述符提供 了一種表示法來重定向文件。因為標準錯誤和文件描述符 2 一樣,我們用這種 表示法來重定向標準錯誤:

ls -l /bin/usr 2> ls-error.txt

注意: 文件描述符 2,要緊挨著放在重定向操作符之前,中間沒有空格。還是看看終端有沒有回顯,ls-error.txt 的內容吧。

4. 重定向標準輸出和錯誤到同一個文件

可能有這種情況,我們希望捕捉一個命令的所有輸出到一個文件。為了完成這個,我們必須同時重定向標準輸出和標準錯誤。有兩種方法來完成任務。

  • 第一個,傳統的方法, 在舊版本 shell 中也有效:ls -l /bin/usr > ls-output.txt 2>&1
    • 使用這種方法,我們完成兩個重定向。首先重定向標準輸出到文件 ls-output.txt,然後 重定向文件描述符 2(標準錯誤)到文件描述符 1(標準輸出)使用表示法 2>&1。

  • 現在的 bash 版本提供了第二種方法,更精簡合理的方法來執行這種聯合的重定向:ls -l /bin/usr &> ls-output.txt

5. 處理不需要的輸出

有時候不想要一個命令的輸出結果,只想把它們扔掉。系統通過重定向輸出結果到一個叫做 "/dev/null" 的特殊文件, 為我們提供了解決問題的方法。這個文件是系統設備,叫做位存儲桶,它可以 接受輸入,並且對輸入不做任何處理。

ls -l /bin/usr 2> /dev/null

6. 標準輸入重定向

什麼?輸入也可以重定向,我有點吃驚,那我們一起來一探究竟吧。

6.1. cat

cat 命令讀取一個或多個文件,然後複製它們到標準輸出。試試 cat < ls-output.txt 吧。看看效果,其實我們是使用 < 輸入重定向,把輸入從鍵盤等輸入設備改成從一個文件的內容作為輸入。如果還沒有理解,你可以在終端只輸入 cat 命令,這時候沒有任何響應,其實 cat 是在等待輸入,我們鍵盤上隨便輸入一些內容,然後按 ctrl + d 告訴 cat 輸入已經達到末尾,看看效果吧。

6.2. 管道線 |

命令從標準輸入讀取數據並輸送到標準輸出的能力被一個稱為管道線的 shell 特性所利用。 使用管道操作符」|」(豎杠),一個命令的標準輸出可以通過管道送至另一個命令的標準輸入:

command1 | command2

來看個例子感受一下管道帶來的便利吧。

ls -l /usr/bin | less

在這個例子中,我們將 ls -l /usr/bin 的結果當成 less 命令的輸入。

6.3. 過濾器

管道線經常用來對數據完成複雜的操作。有可能會把幾個命令放在一起組成一個管道線。 通常,以這種方式使用的命令被稱為過濾器。過濾器接受輸入,以某種方式改變它,然後輸出它。第一個我們想試驗的過濾器是 sort。想像一下,我們想把目錄 /bin 和 /usr/bin 中 的可執行程序都聯合在一起,再把它們排序,然後瀏覽執行結果:

ls /bin /usr/bin | sort | less

因為我們指定了兩個目錄(/bin 和 /usr/bin),ls 命令的輸出結果由有序列表組成, 各自針對一個目錄。通過在管道線中包含 sort,我們改變輸出數據,從而產生一個有序列表。

6.4. uniq - 報道或忽略重複行

uniq 命令經常和 sort 命令結合在一起使用。uniq 從標準輸入或單個文件名參數接受數據有序列表(詳情查看 uniq 手冊頁),默認情況下,從數據列表中刪除任何重複行。所以,為了保證我們的列表中不包含重複句子(也就是出現在目錄 /bin 和 /usr/bin 中重名的程序),我們添加 uniq 到我們的管道線中:

ls /bin /usr/bin | sort | uniq | less

在這個例子中,我們使用 uniq 從 sort 命令的輸出結果中,來刪除任何重複行。如果我們想看到重複的數據列表,讓 uniq 命令帶上 "-d" 選項,就像這樣:

ls /bin /usr/bin | sort | uniq -d | less

6.5. wc - 列印行數、字數和位元組數

直接看例子:wc ls-output.txt

在這個例子中,wc 列印出來三個數字:包含在文件 ls-output.txt 中的行數,單詞數和位元組數, 正如我們先前的命令,如果 wc 不帶命令行參數,它接受標準輸入。」-l」選項限制命令輸出只能 報道行數。添加 wc 到管道線來統計數據,是個很便利的方法。查看我們的有序列表中程序個數, 我們可以這樣做:ls /bin /usr/bin | sort | uniq | wc -l

6.6. grep - 列印匹配行

grep 是個很強大的程序,用來找到文件中的匹配文本。這樣使用 grep 命令:grep pattern [file...]

比如說,我們想在我們的程序列表中,找到文件名中包含單詞 "zip" 的所有文件。這樣一個搜索, 可能讓我們了解系統中的一些程序與文件壓縮有關係。這樣做:

ls /bin /usr/bin | sort | uniq | grep zip

grep 有一些方便的選項:"-i" 使得 grep 在執行搜索時忽略大小寫(通常,搜索是大小寫 敏感的),"-v" 選項會告訴 grep 只列印不匹配的行。

6.7. head / tail - 列印文件開頭部分/結尾部分

有時候你不需要一個命令的所有輸出。可能你只想要前幾行或者後幾行的輸出內容。 head 命令列印文件的前十行,而 tail 命令列印文件的後十行。默認情況下,兩個命令 都列印十行文本,但是可以通過 "-n" 選項來調整命令列印的行數。

也可以結合 | 使用哦。

tail 有一個選項允許你實時地瀏覽文件。當觀察日誌文件的進展時,這很有用,因為它們同時在被寫入。在以下的例子里,我們要查看目錄 /var/log 裡面的信息文件。在一些 Linux 發行版中,要求有超級用戶許可權才能閱讀這些文件。

使用 "-f" 選項,tail 命令繼續監測這個文件,當新的內容添加到文件後,它們會立即出現在屏幕上。這會一直繼續下去直到你輸入 ctrl + c。

6.8. tee - 從 Stdin 讀取數據,並同時輸出到 Stdout 和文件

tee 程序從標準輸入讀入數據,並且同時複製數據 到標準輸出(允許數據繼續隨著管道線流動)和一個或多個文件。當在某個中間處理 階段來捕捉一個管道線的內容時,這很有幫助。來看個例子,我們在 grep 過濾管道線的內容之前,來捕捉整個目錄列表到文件 ls.txt:

ls /usr/bin | tee ls.txt | grep zip

注意到沒有,我們使用 tee 將中間結果保存到了 ls.txt 文件中。

好了,今天的內容就到這裡了,學會了這些重定向的方法,我們在使用 Linux 系統的過程中又多了一些方便。不要死記硬背,能用的地方多用,既能解決麻煩,又學會使用新技能,何樂而不為呢?

歡迎關注微信公眾號:Linux 漫遊之旅,最新文章會在這個公眾號首發,免費提供 CSDN 下載服務。

推薦閱讀:

TAG:Linux | Ubuntu入門 | Ubuntu |