7

問題のデモ用の最小限のコードは次のとおりです: http://pastebin.com/5TXDpSh5

#!/bin/bash
set -e
set -o pipefail

function echoTraps() {
    echo "= on start:"
    trap -p
    trap -- 'echo func-EXIT' EXIT
    echo "= after set new:"
    trap -p
    # we can ensure after script done - file '/tmp/tmp.txt' was not created
    trap -- 'echo SIG 1>/tmp/tmp.txt' SIGPIPE SIGHUP SIGINT SIGQUIT SIGTERM
}

trap -- 'echo main-EXIT1' EXIT

echo "===== subshell trap"
( echoTraps; )

echo "===== pipe trap"
echoTraps | cat

echo "===== done everything"

出力

===== subshell trap
= on start:
= after set new:
trap -- 'echo func-EXIT' EXIT
func-EXIT
===== pipe trap
= on start:
= after set new:
trap -- 'echo func-EXIT' EXIT
===== done everything
main-EXIT1

期待される出力

===== subshell trap
= on start:
= after set new:
trap -- 'echo func-EXIT' EXIT
func-EXIT
===== pipe trap
= on start:
= after set new:
trap -- 'echo func-EXIT' EXIT
func-EXIT                 <---- here is the expected difference
===== done everything
main-EXIT1

NB: OSX 10.9.2 bash (3.2.51) でテストしました - 他のバージョンの bash では、実際の予想される出力と同じ違いがあり、以下で説明します

4

2 に答える 2

0

あなたの娯楽のためのいくつかのテストケースを次に示します。

$ cat traps.sh
#!/bin/bash

echoTraps() {
        echo "entering echoTraps()"

        printf "  traps: %s\n" "$(trap -p)"

        echo "  setting trap"
        trap -- 'echo "func-exit()"' EXIT

        printf "  traps: %s\n" "$(trap -p)"

        echo "exiting echoTraps()"
}

trap -- 'echo "main-exit()"' EXIT

echo "===== calling '( echoTraps; )'"
( echoTraps; )
echo

echo "===== calling 'echoTraps | cat'"
echoTraps | cat
echo

echo "===== calling '( echoTraps; ) | cat'"
( echoTraps; ) | cat
echo

echo "===== calling '{ echoTraps; } | cat'"
{ echoTraps; } | cat
echo

バッシュ-4.2.25(1)

$ ./traps.sh
===== calling '( echoTraps; )'
entering echoTraps()
  traps:
  setting trap
  traps: trap -- 'echo "func-exit()"' EXIT
exiting echoTraps()
func-exit()

===== calling 'echoTraps | cat'
entering echoTraps()
  traps: trap -- 'echo "main-exit()"' EXIT
  setting trap
  traps: trap -- 'echo "func-exit()"' EXIT
exiting echoTraps()

===== calling '( echoTraps; ) | cat'
entering echoTraps()
  traps:
  setting trap
  traps: trap -- 'echo "func-exit()"' EXIT
exiting echoTraps()
func-exit()

===== calling '{ echoTraps; } | cat'
entering echoTraps()
  traps: trap -- 'echo "main-exit()"' EXIT
  setting trap
  traps: trap -- 'echo "func-exit()"' EXIT
exiting echoTraps()

main-exit()

バッシュ-4.3.0(1)

$ bash-static-4.3.2/bin/bash-static traps.sh
===== calling '( echoTraps; )'
entering echoTraps()
  traps:
  setting trap
  traps: trap -- 'echo "func-exit()"' EXIT
exiting echoTraps()
func-exit()

===== calling 'echoTraps | cat'
entering echoTraps()
  traps: trap -- 'echo "main-exit()"' EXIT
  setting trap
  traps: trap -- 'echo "func-exit()"' EXIT
exiting echoTraps()

===== calling '( echoTraps; ) | cat'
entering echoTraps()
  traps:
  setting trap
  traps: trap -- 'echo "func-exit()"' EXIT
exiting echoTraps()
func-exit()

===== calling '{ echoTraps; } | cat'
entering echoTraps()
  traps: trap -- 'echo "main-exit()"' EXIT
  setting trap
  traps: trap -- 'echo "func-exit()"' EXIT
exiting echoTraps()
func-exit()

main-exit()

結論: このようなエッジケースに頼らないでください。サブシェルとパイプに関する他の矛盾 (トラップについてではない) を調査したことを覚えており、bashソース コードに頭を悩ませようとしたのですが、そのルートをたどりたくないし、特定の状況でのように動作する理由を理解しようとはしません。 (コードは本当にひどいです、ところで)。ご覧のとおり、いくつかのことが「修正」されているように見えますが、私の例は両方とも既にあなたのものとは異なる動作をしています。

于 2014-03-06T15:37:24.027 に答える