Unix 命令默認從標准輸入設備(stdin)獲取輸入,將結果輸出到標准輸出設備(stdout)顯示。一般情況下,標准輸入設備就是鍵盤,標准輸出設備就是終端,即顯示器。
1. 輸出重定向
命令的輸出不僅可以是顯示器,還可以很容易的轉移向到文件,這被稱為輸出重定向。
命令輸出重定向的語法為:
command > file
如:將用戶信息輸出到 test.sh文件中(test.sh文件中含有內容)
[root@centoszang testShell]# ls choose.sh menuChoose myShell.sh test.sh [root@centoszang testShell]# who > test.sh [root@centoszang testShell]# cat test.sh root tty1 2018-06-18 08:44 (:0) root pts/0 2018-06-18 14:55 (192.168.177.1)
可以看到,輸出重定向會覆蓋文件內容,如果不希望文件內容被覆蓋,可以使用 >> 追加到文件末尾
[root@centoszang testShell]# echo "Hello EveryOne" >> test.sh [root@centoszang testShell]# cat test.sh root tty1 2018-06-18 08:44 (:0) root pts/0 2018-06-18 14:55 (192.168.177.1) Hello EveryOne
2. 輸入重定向
和輸出重定向一樣,Unix 命令也可以從文件獲取輸入。
command < file
這樣,本來需要從鍵盤獲取輸入的命令會轉移到文件讀取內容。
[root@centoszang testShell]# wc -l test.sh #計算 test.sh 文件中的行數 3 test.sh [root@centoszang testShell]# wc -l < test.sh 3
上面兩個例子的結果不同:第一個例子,會輸出文件名;第二個不會,因為它僅僅知道從標准輸入讀取內容。
3. 重定向深入講解
3.1 基本介紹
一般情況下,每個 Unix/Linux 命令運行時都會打開三個文件:
- 標准輸入文件(stdin):stdin的文件描述符為0,Unix程序默認從stdin讀取數據。
- 標准輸出文件(stdout):stdout 的文件描述符為1,Unix程序默認向stdout輸出數據。
- 標准錯誤文件(stderr):stderr的文件描述符為2,Unix程序會向stderr流中寫入錯誤信息。
默認情況下,command > file 將 stdout 重定向到 file,command < file 將stdin 重定向到 file。
如果希望 stderr 重定向或追加到 file,可以按照如下語法:
command 2> file #重定向 command 2 >> file #追加
如下代碼是將標准錯誤信息(stderr)也輸出到log文件
將 stdout 和 stderr 合並后重定向到 log
重定向到某個文件描述符時,必須在文件描述符前面添加 & 符號。必須這樣的原因:類似1,2這樣的文件描述符也是標准的Linux文件名稱,添加 & 符號以做區分。
3.2 兩種(合並)重定向的區別
考慮當我們將stdout和stderr輸出時,command > file 2> file 與 command > file 2>&1 這兩種語法效果一樣嗎?
效果貌似一樣:因為不管是command產生的標准輸出信息還是標准錯誤信息都重定向到了file文件里。確實如此,但也有讓人意料之外的地方:
command > file 2> file 命令把STDOUT和STDERR都直接送到file文件中,file文件會被打開兩次,這樣STDOUT和STDERR會相互覆蓋。該命令執行時相當於兩個進程同時向同一個文件中寫數據,你寫你的,我寫我的,也不進行同步,寫完拉倒。打開文件一看,數據重疊,亂七八糟。
command > file 2>&1 命令把STDOUT直接送往file文件,而STDERR經由STDOUT的通道把數據信息送到file文件中。此時,file文件只被打開了一次,因此標准輸出數據和標准錯誤數據不會相互覆蓋,而是井然有序。
從I/O效率上來說,command > file 2> file 相比於 command > file 2>&1 要低,而且會出現數據相互覆蓋的情況。因此,我們一般會使用后面這條命令。
3.3 可用的重定向命令列表
3.4 在同一命令中進行多次輸出重定向
如果我們在同一個命令中進行了多次輸出重定向操作,會出現什么情況呢?最終命令的輸出會重定向到最后一次重定向的位置。
echo hello world > log.txt 1>/dev/tty1 2>&1 命令首先把標准輸出重定向到log.txt文件,由於當前目錄下並不存在該文件,因此會創建該文件,並把文件清空;接着命令又把標准輸出重定向到了終端顯示器;最后又把標准錯誤重定向到了標准輸出。因此命令的輸出還是被發送到了終端顯示器上,命令結束,文件關閉,結果log.txt文件里什么數據都沒有寫入,只是創建了一個空白的文件。
4. Here Document
Here Document 目前沒有統一的翻譯,這里暫譯為”嵌入文檔“。Here Document 是 Shell 中的一種特殊的重定向方式。
語法:
command << delimiter
document
delimiter
它的作用是將兩個 delimiter 之間的內容(document) 作為輸入傳遞給 command。
注意:
- 結尾的delimiter 一定要頂格寫,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 縮進。
- 開始的delimiter前后的空格會被忽略掉。
在shell腳本中調用vi編輯器,輸入的內容由here document來提供。
#! /bin/bash vi abc.txt <<EOF i #進入insert模式 Here is a document! #輸入文本內容 ^[ #這個符號是在Ctrl+v下按ESC鍵,意為按下ESC退出編輯模式 :wq #保存退出 EOF
需要注意的是,vi編輯器為交互式編輯器,一般不用在shell腳本中使用,除非有特殊需求。一般在shell腳本中都調用ed編輯器。
5. /dev/null 文件
如果希望執行某個命令,但又不希望在屏幕上顯示輸出結果,那么可以將輸出重定向到 /dev/null。
語法:
command > /dev/null
/dev/null 是一個特殊的文件,寫入到它的內容都會被丟棄;如果嘗試從該文件讀取內容,那么什么也讀不到。但是 /dev/null 文件非常有用,將命令的輸出重定向到它,會起到”禁止輸出“的效果。在只想測試命令而不想有任何輸出時較有用。
command > /dev/null 2>&1 #屏蔽 stdout 和 stderr
另外,在只想刪除文件內容,而不刪除文件時,可以使用如下方法
參考: