在命令列介面的世界裡,程式通常會與三種標準資料流互動:
stdin):程式接收輸入的地方(通常來自鍵盤)。stdout):程式送出一般輸出的地方(通常送到終端機畫面)。stderr):程式送出錯誤訊息的地方(通常送到終端機畫面)。還記得我們在管線與指令清單那一章介紹過這些嗎?
管線可以視為重導向的一種形式:某個程式的標準輸出會直接送到另一個程式的標準輸入。 我們已經介紹過管線了。 這個概念要談的是如何重導向到檔案,以及從檔案重導向。
Shell 重導向是強大的機制,讓你能改變這些資料流的去向。 你可以讓程式不從鍵盤讀取、不寫到螢幕,改成從檔案重導向輸入,或把輸出送到檔案。 這讓你能靈活地控制程式與資料互動的方式。
以下是幾個最常見的重導向運算子,以及它們的作用:
>(輸出重導向)用途:把指令的標準輸出(stdout)重導向到檔案。
行為:
範例:
# Sends the output of 'ls -l' to 'file_listing.txt'
ls -l > file_listing.txt
重導向會在指令執行之前完成。 這表示你不能重導向到同一個你需要讀取的檔案。
date > date.txt # populate the file with the current date
cat date.txt > date.txt # 'date.txt' is now empty!
在上面範例的第二個指令中,
>>(附加輸出重導向)用途:把指令的標準輸出(stdout)附加到檔案。
行為:
範例:
# Adds "Another line" to the end of the file
echo "Another line" >> file_listing.txt
<(輸入重導向)用途:把指令的標準輸入(stdin)從檔案重導向。
行為:指令會從指定的檔案讀取輸入,而不是從鍵盤。
範例:
# 'tr' reads from 'lowercase.txt' and
# output is redirected to 'uppercase.txt'
tr 'a-z' 'A-Z' < lowercase.txt > uppercase.txt
2>(錯誤重導向):stderr)重導向到檔案。# Error message from 'rm' is sent to 'error_log.txt'
rm non_existent_file 2> error_log.txt
你可以用2>>把標準錯誤_附加_到檔案。
還有一些重導向可以合併 stdin 和 stderr。
詳情請參閱手冊。
/dev/null/dev/null 是一個特殊的檔案,它
它有時被稱為「位元桶」。 它很適合用來抑制輸出或錯誤。
some_command > /dev/null # Discards stdout
some_command 2> /dev/null # Discards stderr
# Using /dev/null as input will prevent the command
# from reading data from the keyboard
some_command < /dev/null
你可以一次給多個重導向。
some_command < input.txt > output.txt 2> error.txt
重導向可以被複製。
# send stderr to the same destination as stdout
some_command > output.txt 2>&1
當你看到2>&1時,可以把它讀成「把 stderr 重導向到 stdout 目前指向的地方」。
Bash 會嚴格地從左到右處理重導向指令,這表示你可以這樣做:
# redirect stdout to 'output1.txt'
# redirect stderr to the same place
# then change stdout to 'output2.txt'
some_command > output1.txt 2>&1 > output2.txt
在 shell 程式設計以及像 Linux/Unix 這類作業系統的脈絡中,檔案描述符(FD)是一個非負整數,做為開啟的檔案或 I/O(輸入/輸出)資源的識別碼或控制代碼。 你可以把它想成作業系統用來追蹤開啟檔案與資料流的標籤或編號。
你在重導向左邊看到的數字就是檔案描述符。
標準 I/O 資料流會拿到前三個檔案描述符:
新的檔案描述符可以用exec指令和重導向運算子來設定或建立。
# create FD 3 as a copy of stdout
exec 3>&1
# send stdout to a log file
exec > log.txt
# then redirect both stdout and file descriptor 3
echo "some debug message" >&3 # displayed in the terminal
some_command 2>&1 # stdout and stderr send to 'log.txt'
這個技巧看起來挺複雜的,但在某些情況下非常有用:當你的指令碼是被其他軟體套件執行,而標準輸出會被那個軟體自動擷取時。
這個 track 用來執行單元測試的bats指令就是這樣運作的:bats會擷取測試的 stdout 和 stderr,但送到 FD 3 的除錯訊息會顯示在終端機上。
重導向為什麼有用?
Shell 重導向讓你精細地控制程式與資料互動的方式,幫助你建構複雜的工作流並有效管理資訊。