2>&1是什麼意思?介紹輸出重新導向

剛開始接觸shell腳本,看到指令後面接著「2>&1」感到茫然,孰悉輸出重新導向符號「>」,就不難理解,首先要介紹檔案描述符。

檔案描述符

檔案描述符共有3個,1個輸入,2個輸出,如下表
stdio.h 名稱 中譯
0 stdin Standar Input 標準輸入
1 stdout Standar Output 標準輸出
2 stderr Standar Error 標準錯誤輸出

將輸出文字記錄於檔案中

將文字記錄於檔案,普遍的寫法為 echo "standar output" > file.txt 其實在「>」前面省略了1,也就是標準輸出(stdout),完整的寫法應為 echo "standar output" 1> file.txt 檔案描述符1是預設值,通常省略不寫,而在「>」後有無空格都是符合語法的,可依個人程式風格自訂。

假設指令輸出有錯誤訊息,例如當前目錄沒有xxx這個檔案,用ls去列出xxx就會出錯,執行顯示為 $ ls xxx ls: cannot access 'xxx': No such file or directory 把標準錯誤輸出(stderr)記錄於檔案中,可寫作 ls xxx 2> file.txt 就可以將「ls: cannot access 'xxx': No such file or directory」存於file.txt。 另一種常見的應用,是想不顯示錯誤訊息,就把標準錯誤輸出丟進/dev/null。 ls xxx 2> /dev/null

導向檔案描述符

若想將「標準輸出」、「標準錯誤輸出」合併,一般的作法是將「標準錯誤輸出」併入「標準輸出」。但若寫為 ls xxx 2>1 會發現多了一個命名為1的檔案,而檔案內容是「ls: cannot access 'xxx': No such file or directory」,這與我們想要的結果不符,須用「>&」來表示後方的檔案,是一個檔案描述符號, ls xxx 2>&1 這才是我們想要的合併結果,同樣的,在「>&」後有無空格都是符合語法的,可依個人程式風格自訂。
相反的,若是要將「標準輸出」併入「標準錯誤輸出」, echo "error output" 1>&2 不過,之前提到標準輸出是預設值,所以常見的寫法會是 echo "error output" >&2

同時指定1、2的導向

先建個測試腳本op.sh,檔案內容如下 $ cat op.sh #!/bin/bash echo "standar output" echo "error output" >&2 執行後,標準輸出為「standar output」,標準錯誤輸出為「error output」,可以將2個輸出記錄到不同檔案 ./op.sh > file1.txt 2> file2.txt 導向到相同的檔案,不可以寫成 ./op.sh > file.txt 2> file.txt 這樣會相互覆蓋,若要先存標準輸出,再存標準錯誤輸出,可以使用附加符號「>>」寫成 ./op.sh > file.txt 2>> file.txt 但大多時候,是希望以執行時間依序記錄,不區分標準輸出與標準錯誤輸出,此時,可以使用合併的方式,將2的輸出併於1,再將1寫入檔案,寫法為 ./op.sh > file.txt 2>&1 這邊要注意的是,「2>&1」要寫在後面,才會「標準錯誤輸出」併入「標準輸出」後,再將「標準輸出」記錄於file.txt,這是由於「導向」類似於連結、捷徑的概念,預設1、2都是導向螢幕,也就是輸出顯示在螢幕上,先設定1導向file.txt,再設定2導向1,這時導向的1已導向file.txt,2導向1也就是導向file.txt。也有另一種簡易,但較為少見的寫法 ./op.sh &> file.txt 符號「&」代表導向檔案描述符1與2,將「&」、「>」交換位置,「&>」與「>&」的語意一樣,也是較少見。 ./op.sh >& file.txt

空格、>、&的順序

為了理解執行結果,先將測試腳本op.sh加入印出輸入參數,檔案內容修改為 $ cat op.sh #!/bin/bash echo "para: $@" echo "standar output" echo "error output" >&2 若在「>」前加入空格,例如$ ./op.sh 2 > file.txt會被解讀成$ ./op.sh 2 1> file.txt,所以執行結果2變成第一個輸入參數,而標準錯誤輸出由螢幕顯示,標準輸出則存於file.txt中,如下 $ ./op.sh 2 > file.txt error output $ cat file.txt para: 2 standar output 在「>」與「&」中間加入空格,是錯誤語法 $ ./op.sh 2> &1 bash: syntax error near unexpected token `&' 在「>&」後加入空格,與無空格時$ ./op.sh 2>&1相同語意,這是之前提到的,可依個人程式風格調整。

若是將./op.sh 2>&1中的「&」、「>」交換位置會如何呢?會被解讀成./op.sh 2 &>1,所以執行結果2變成第一個輸入參數,而標準輸出、標準錯誤輸均存於檔案1中,如下 $ ./op.sh 2&>1 $ cat 1 para: 2 standar output error output

總結

上述的說明理解後,方便複習,統整常見、常用的如下表
執行命令 語意 效果
command > file.txt command 1>file.txt
導向說明:
1 → file.txt
「標準輸出」寫入檔案file.txt
command > file.txt 2>&1
command &> file.txt
command 1>file.txt 2>&1
導向說明:
1 → file.txt
2 → 1 → file.txt
「標準輸出」與「標準錯誤輸出」寫入檔案file.txt
command > /dev/null command 1>/dev/null
導向說明:
1 → NULL
丟棄「標準輸出」
command > /dev/null 2>&1
command &> /dev/null
command 1>/dev/null 2>&1
導向說明:
1 → NULL
2 → 1 → NULL
丟棄「標準輸出」與「標準錯誤輸出」
echo "error message" >&2 echo "error message" 1>&2
導向說明:
1 → 2
設定「標準錯誤輸出」為「error message」

留言

這個網誌中的熱門文章

Python的10進制與16進制轉換

設定CPU的Cache模式:MTRR

ls -l 顯示出現亂碼