2>&1是什麼意思?介紹輸出重新導向
剛開始接觸shell腳本,看到指令後面接著「2>&1」感到茫然,孰悉輸出重新導向符號「>」,就不難理解,首先要介紹檔案描述符。
檔案描述符
檔案描述符共有3個,1個輸入,2個輸出,如下表
| 值 | stdio.h | 名稱 | 中譯 |
|---|---|---|---|
| 0 | stdin | Standar Input | 標準輸入 |
| 1 | stdout | Standar Output | 標準輸出 |
| 2 | stderr | Standar Error | 標準錯誤輸出 |
將輸出文字記錄於檔案中
將文字記錄於檔案,普遍的寫法為
假設指令輸出有錯誤訊息,例如當前目錄沒有xxx這個檔案,用ls去列出xxx就會出錯,執行顯示為
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>&1command &> 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>&1command &> /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」 |
留言
張貼留言