每一個進程都至少有3個信道:「標準輸入」(stdin)、「標準輸出」(stdout)和「標準出錯」(stderr)。內核給每一個進程都設置了這3個信道,因此進程自己沒必要知道這三個信道通到哪裏。舉例來講,它們可能鏈接到一個終端窗口、一條網絡鏈接,或者屬於另外一個進程的信道。shell
UNIX有一個統一的I/O模型,在這個模型中,每一個信道都以一個整數來命名,它叫作文件描述符。文件描述符0、1以及2是系統預留的。bash
0 —— stdin(標準輸入)
1 —— stdout(標準輸出)
2 —— stderr(標準錯誤)網絡
大多數命令都接受從stdin來的輸入,而且把本身的輸出寫到stdout,而把出錯消息寫到stderr。有了這樣的約定,用戶就能把命令像積木同樣串起來,建立出混合管道。spa
shell將<、>和>>解釋成指令,用來把一條命令的輸入或者輸出重定向到一個文件。<符號把這條命令的stdin和已有的某個文件的內容聯繫起來;>符號重定向stdout,會替換文件的現有內容;>>符號重定向stdout,會給文件追加內容。調試
例1:重定向或保存到一個文件中code
echo "This is a test message1." > temp.txt
例2:將文本追加到目標文件中server
echo "This is a test message2." >> temp.txt
爲了把stdout和stderr都重定向到同一個地方,能夠用>&這個符號。僅僅重定向stderr的話,則用2>。
命令find演示了想要分開處理stdout和stderr的緣由,由於它會在兩個信道提供輸出,特別是以非特權用戶身份運行的時候。例如,像下面這條命令:排序
find / -name core 有時候在輸出中可能包含一些沒必要要的信息(好比調試消息),從而把真正的結果給淹沒在混亂的輸出裏。要消除全部出錯消息,能夠用這條命令: find / -name core 2> /dev/null
要把匹配路徑的清單保存在一個文件裏,可使用以下命令:進程
find / -name core > temp.txt 2> /dev/null
這一行命令把匹配的路徑發到temp.txt這個文件,丟棄出錯消息,向終端窗口什麼都不發。
要把一條命令的stdout鏈接到另外一條命令的stdin上,能夠用|這個符號,它常叫作管道。io
例子:
ps -ef | grep httpd
這條命令運行ps產生一份進程清單,由管道送給grep命令選出包含httpd這個詞的若干行。grep命令的輸出沒有重定向,因此匹配的結果都出如今終端窗口裏。
cut -d: -f7 < /etc/passwd | sort -u
這條命令用cut命令從/etc/passwd文件裏把每一個用戶的shell的路徑選出來。接着,列出的shell的路徑都經過sort-u進行處理,產生的清單中,路徑名不但依次排序,且路徑名只出現一次。
要讓第二條命令只有在第一條命令成功完成以後執行,能夠用一個&&符號把兩條命令隔開。
cd /usr/local/ && pwd
這條命令進入/usr/local/目錄下,而後顯示當前路徑。這裏用一個表示「邏輯與」的符號,那麼就可能形成混亂。不要想得太多;僅僅把它當作一個shell的習慣用法就好了。
相反,||這個符號代表,只有前一條命令執行不成功時,才執行後面的命令。
字一個腳本里,能夠用反斜線把一條命令分紅多行來寫,從而把出錯處理代碼和命令管道的其餘部分區分開來;
cp --preserver --recursive /etc/* /spare/backup \ || echo "Did NOT make backup"
要實現相反的效果——將多條命令整合在一行裏——能夠用分號做爲語句分隔符。
將腳本內部的文本塊進行重定向
有時候,咱們須要對文本塊(多行文本)進行重定向,就像對標準輸入作的那樣。考慮一個特殊狀況:源文本就位於shell腳本中。一個實用的例子是向log文件中寫入頭部數據,能夠按照下面的方法完成:
#!/bin/bash cat<<EOF>log.txt LOG FILE HEADER This is a test log file Function: System statistics EOF
在cat <
cat log.txt LOG FILE HEADER This is a test log file Function: System statistics