重導

重導向 在 Bash

{other: "%{count} 個練習"}

關於 重導向

在命令列介面的世界裡,程式通常會與三種標準資料流互動:

  1. 標準輸入(stdin):程式接收輸入的地方(通常來自鍵盤)。
  2. 標準輸出(stdout):程式送出一般輸出的地方(通常送到終端機畫面)。
  3. 標準錯誤(stderr):程式送出錯誤訊息的地方(通常送到終端機畫面)。

還記得我們在管線與指令清單那一章介紹過這些嗎?

Note

管線可以視為重導向的一種形式:某個程式的標準輸出會直接送到另一個程式的標準輸入。 我們已經介紹過管線了。 這個概念要談的是如何重導向到檔案,以及從檔案重導向。

Shell 重導向是強大的機制,讓你能改變這些資料流的去向。 你可以讓程式不從鍵盤讀取、不寫到螢幕,改成從檔案重導向輸入,或把輸出送到檔案。 這讓你能靈活地控制程式與資料互動的方式。

常見的重導向運算子

以下是幾個最常見的重導向運算子,以及它們的作用:

>(輸出重導向)

  • 用途:把指令的標準輸出(stdout)重導向到檔案。

  • 行為:

    • 如果檔案不存在,就會建立它。
    • 如果檔案已存在,內容會被覆寫。
  • 範例:

    # Sends the output of 'ls -l' to 'file_listing.txt'
    ls -l > file_listing.txt
    
Caution

重導向會在指令執行之前完成。 這表示你不能重導向到同一個你需要讀取的檔案。

date > date.txt         # populate the file with the current date
cat date.txt > date.txt # 'date.txt' is now empty!

在上面範例的第二個指令中,

  1. Bash 會先截斷重導向中指定的檔案。這會清掉原本的內容,留下一個空檔案。
  2. 接著 bash 讀取這個剛變成空的檔案。
  3. 然後 bash 把內容(也就是空無一物)寫回檔案。

>>(附加輸出重導向)

  • 用途:把指令的標準輸出(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
Advanced

檔案描述符

在 shell 程式設計以及像 Linux/Unix 這類作業系統的脈絡中,檔案描述符(FD)是一個非負整數,做為開啟的檔案或 I/O(輸入/輸出)資源的識別碼或控制代碼。 你可以把它想成作業系統用來追蹤開啟檔案與資料流的標籤或編號。

你在重導向左邊看到的數字就是檔案描述符。

標準 I/O 資料流會拿到前三個檔案描述符:

  • 標準輸入是 FD 0
  • 標準輸出是 FD 1
  • 標準錯誤是 FD 2

新的檔案描述符可以用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 指令碼的必備工具。

Shell 重導向讓你精細地控制程式與資料互動的方式,幫助你建構複雜的工作流並有效管理資訊。

透過 GitHub 編輯 連結會在新視窗或分頁中開啟