Bash
Bash重定向奇怪的行為
當我遇到一個有趣的結果時,我正忙於擷取退出程式碼和重定向
stdout
以及案例陳述,我希望有人能對此有所了解。stderr
我正在使用 bash 5.1.16。
此塊可用於複製我看到的行為:
#!/bin/sh -x cleanup () { case $? in 1) echo "message 1" ;; 9) echo "message 2" ;; esac } trap cleanup EXIT case 0 in 0) exit 1 ;; 2) echo "yay" ;; esac > /dev/null 2>&1
xtrace 輸出
> /dev/null 2>&1
:+ trap cleanup EXIT
沒有的 xtrace 輸出
> /dev/null 2>&1
:+ trap cleanup EXIT + case 0 in + exit 1 + cleanup + case $? in + echo 'message 1' message 1
這裡發生了什麼?重定向是如何導致 case 語句根本不執行的?
陷阱在
EXIT
呼叫陷阱時使用已到位的重定向執行。在您的程式碼中,呼叫exit 1
maincase
語句會導致cleanup
函式從該語句繼承重定向。一個不向標準輸出列印任何內容的簡短範例:
cleanup () { echo bye } trap cleanup EXIT exit >/dev/null
刪除
>/dev/null
以獲得腳本輸出bye
。生成的跟踪輸出
set -x
被寫入標準錯誤流,並且您的程式碼也將此流重定向到/dev/null
。簡而言之,您的函式case
語句被執行,但是您丟棄了腳本的所有輸出,因此您不會看到它的輸出echo
,也不會看到跟踪輸出。另請注意,其他一些 shell,如
dash
andksh
,不會以這種方式執行。要在 shell 中解決此問題
bash
,您可以在腳本開頭複製標準錯誤文件描述符,然後在cleanup
函式中顯式使用它。我為此使用標準錯誤流,因為我假設它將用於診斷消息。你的程式碼加上我的補充:
#!/bin/bash -x exec {fd}>&2 cleanup () { case $? in 1) echo "message 1" ;; 9) echo "message 2" ;; esac >&$fd } trap cleanup EXIT case 0 in 0) exit 1 ;; 2) echo "yay" ;; esac > /dev/null 2>&1
由 shell 分配並分配給的描述符
fd
將是 10 或更高。由於
sh
並非總是如此bash
,我還更改了#!
-line 以顯式呼叫bash
執行檔。執行這個:
$ ./script + exec + trap cleanup EXIT message 1