理解 shell 指令碼中的常見用法: 2>&1

rovast發表於2021-02-08

在我們接觸的 shell 指令碼中,對 2>&1 一定不陌生,比如 ls foo > /dev/null 2>&1

本文就來解釋下 2>&1 究竟做了什麼,並且是如何起作用的。

一、I/O 重定向簡介

「重定向」是計算機用來把命令的輸出從一個地方,輸出到另一個地方。舉個例子,預設情況下,我們使用 cat 指令可以把一個檔案的內容列印到終端:

$ cat foo.txt
foo
bar
baz

但是,我們可以把輸出重定向到另外地方。此例中,我們可以把輸出重定向到 output.txt 中:

$ cat foo.txt > output.txt

$ cat output.txt
foo
bar
baz

注意,在執行第一行命令 cat foo.txt > output.txt 時,我們在螢幕上看不到任何輸出。我們把原來應該列印到螢幕的內容,重定向到 output.txt 了,所以螢幕上不會有任何輸出了。

這裡,「本來應該列印到螢幕的內容」,就是標準輸出,即 stdout(standard output)

除了標準輸出可以接收程式的輸出之外,還有一個地方可以,叫 標準錯誤輸出,即 stderr(standard error)。stderr 用來接收程式的錯誤訊息。例如,我們 cat 了一個不存在的檔案:

$ cat nop.txt > output.txt
cat: nop.txt: No such file or directory

我們看到,雖然我們要求程式把輸出重定向到 output.txt,但是我們還是在螢幕上看到了錯誤訊息輸出。這是因為我們只是重定向了 standard output,而不是 standard error。

二、檔案描述符(fd)簡介

檔案描述符(file descriptor)簡單來說,就是一個正整數,用來代表一個開啟的檔案。比如當前我們有 100 各開啟的檔案,那麼就有 100 個檔案描述符。

唯一需要補充的是,在 Unix 系統中,「一切皆檔案」。

同時我們還應該知道,對於標準輸出(stdout)和標準錯誤輸出(stderr),也有對應的檔案描述符。我們使用 1 和 2 來分別表示 stdout 和 stderr 所在的位置。

三、融合上述知識

回到我們的第一個示例,我們還可以有另外一種寫法

# 寫法一
$ cat foo.txt > output.txt

# 等價寫法二
$ cat foo.txt 1> output.txt

這裡的 1 就是用來代表 stdout 的檔案描述符。語法是 [FILE_DESCRIPTOR]>。我們看到把 1 省略的寫法 >只是 1> 的快捷寫法而已。

對於重定向到 stderr 的場景,我們只需要在右邊的檔案前面加上檔案描述符即可

$ cat nop.txt 2> error.txt

$ cat error.txt
cat: nop.txt: No such file or directory

你看,這樣就生效了。這會兒,你大概知道 2>&1 是怎樣工作的,讓我們來總結總結。

我們使用 &1 來表示檔案描述符1(stdout)的地址。當你使用 2>&1 時,其實就是在說:把 stderr 的輸出重定向到 stdout 的地方。這樣,我們就可以把程式的標準輸出和錯誤輸出都輸出到同一個地方了。

$ cat foo.txt > output.txt 2>&1

$ cat output.txt
foo
bar
baz

$ cat nop.txt > output.txt 2>&1

$ cat output.txt
cat: nop.txt: No such file or directory

四、總結

  • 程式可以把輸出傳送到兩個地方:標準輸出(stdout,standard output)和標準錯誤輸出(stderr,standard error)。
  • 你可以把輸出重定向到另一個地方(比如檔案)
  • 檔案描述符1和2 可以分別用來表示 stdout 和 stderr
  • command > outputcommand 1> output 的縮寫
  • 可以使用 &[FILE_DESCRIPTOR] 來引用檔案描述符的值(或者叫指向檔案描述符的地址)
  • 使用 2>&1 來重定向 stderr 的輸出至 stdout 的地方(你可以用 1>&2 來進行反向操作)
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章