Bash

Bash重定向奇怪的行為

  • June 3, 2022

當我遇到一個有趣的結果時,我正忙於擷取退出程式碼和重定向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 1maincase語句會導致cleanup函式從該語句繼承重定向。

一個不向標準輸出列印任何內容的簡短範例:

cleanup () {
       echo bye
}

trap cleanup EXIT

exit >/dev/null

刪除>/dev/null以獲得腳本輸出bye

生成的跟踪輸出set -x被寫入標準錯誤流,並且您的程式碼也將此流重定向到/dev/null。簡而言之,您的函式case語句執行,但是您丟棄了腳本的所有輸出,因此您不會看到它的輸出echo,也不會看到跟踪輸出。

另請注意,其他一些 shell,如dashand ksh,不會以這種方式執行。

要在 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

引用自:https://unix.stackexchange.com/questions/704906