前言
有時候我們常看到類似這樣的腳本調用:
./test.sh > log.txt 2>&1
這里的2>&1是什么意思?該如何理解?
先說結論:上面的調用表明將./test.sh的輸出重定向到log.txt文件中,同時將標準錯誤也重定向到log.txt文件中。
有何妙用
(如果已經明白是什么作用,可跳過此小節)
上面到底是什么意思呢?我們來看下面的例子,假如有腳本test.sh:
#!/bin/bash date #打印當前時間 while true #死循環 do #每隔2秒打印一次 sleep 2 whatthis #不存在的命令 echo -e "std output" done
腳本中先打印當前日期,然后每隔2秒執行whatthis并打印一段字符。由于系統中不存在whatthis命令,因此執行會報錯。
假如我們想保存該腳本的打印結果,只需將test.sh的結果重定向到log.txt中即可:
./test.sh > log.txt
執行結果如下:
ubuntu$ ./test.sh >log.txt ./test.sh: 行 7: whatthis: 未找到命令
我們明明將打印內容重定向到log.txt中了,但是這條錯誤信息卻沒有重定向到log.txt中。如果你是使用程序調用該腳本,當查看腳本日志的時候,將會完全看不到這條錯誤信息。而使用下面的方式則會將出錯信息也重定向到log.txt中:
./test.sh > log.txt 2>&1
以這樣的方式調用腳本,可以很好的將錯誤信息保存,幫助我們定位問題。
如何理解
每個程序在運行后,都會至少打開三個文件描述符,分別是0:標準輸入;1:標準輸出;2:標準錯誤。
例如,對于前面的test.sh腳本,我們通過下面的步驟看到它至少打開了三個文件描述符:
./test.sh #運行腳本 ps -ef|grep test.sh #重新打開命令串口,使用ps命令找到test.sh的pid hyb 5270 4514 0 19:20 pts/7 00:00:00 /bin/bash ./test.sh hyb 5315 5282 0 19:20 pts/11 00:00:00 grep --color=auto test.sh
可以看到test.sh的pid為5270,進入到相關fd目錄:
cd /proc/5270/fd #進程5270所有打開的文件描述符信息都在此 ls -l #列出目錄下的內容 0 -> /dev/pts/7 1 -> /dev/pts/7 2 -> /dev/pts/7 255 -> /home/hyb/workspaces/shell/test.sh
可以看到,test.sh打開了0,1,2三個文件描述符。同樣的,如果有興趣,也可以查看其他運行進程的文件描述符打開情況,除非關閉了否則都會有這三個文件描述符。
那么現在就容易理解前面的疑問了,2>&1表明將文件描述2(標準錯誤輸出)的內容重定向到文件描述符1(標準輸出),為什么1前面需要&?當沒有&時,1會被認為是一個普通的文件,有&表示重定向的目標不是一個文件,而是一個文件描述符。在前面我們知道,test.sh >log.txt又將文件描述符1的內容重定向到了文件log.txt,那么最終標準錯誤也會重定向到log.txt。我們同樣通過前面的方法,可以看到test.sh進程的文件描述符情況如下:
0 -> /dev/pts/7 1 -> /home/hyb/workspaces/shell/log.txt 2 -> /home/hyb/workspaces/shell/log.txt 255 -> /home/hyb/workspaces/shell/test.sh
我們可以很明顯地看到,文件描述符1和2都指向了log.txt文件,也就得到了我們最終想要的效果:將標準錯誤輸出重定向到文件中。
它們還有兩種等價寫法:
./test.sh >& log.txt ./test.sh &> log.txt
總結
我們總結一下前面的內容:
- 程序運行后會打開三個文件描述符,分別是標準輸入,標準輸出和標準錯誤輸出。
- 在調用腳本時,可使用2>&1來將標準錯誤輸出重定向。
- 只需要查看腳本的錯誤時,可將標準輸出重定向到文件,而標準錯誤會打印在控制臺,便于查看。
- >>log.txt會將重定向內容追加到log.txt文件末尾。
- 通過查看/proc/進程id/fd下的內容,可了解進程打開的文件描述符信息。
思考
下面的調用會將標準錯誤輸出重定向到文件中嗎?為什么?
./test.sh 2>&1 >log.txt
轉載 https://mp.weixin.qq.com/s/x0m8a1ytL3zNhk_4tNUPCw