記事

Last Modified:

同じシグナルに複数個のtrapを仕掛ける方法 #Shell

同じシグナルに何個かtrapを仕掛けたいけど、trapは上書きされてしまうので最後に仕掛けたコマンドしか実行されない。

解決

ちょっとやっつけな感じだけど、 trap -p で現在の内容が出力されるので

at_exit () {
  trap "$1 ; $(trap -p EXIT | sed -E "s/^trap -- '(.*)' EXIT\$/\\1/")" EXIT
}

at_exit 'echo first'
at_exit 'echo second'

ってな感じで;で繋いだコマンドで再定義していけば追記していける。

汎用的にする

汎用的にするため、trapを正しく再定義すればこうなる。

trap () {
  if ((($# == 3)) && [[ $1 == '--' ]]) || ((($# == 2)) && [[ ${1:0:1} != '-' ]])
  then
    if (($# == 3)) && [[ $1 == '--' ]]
    then
       shift
    fi
    set -- -- "$1 ; $(builtin trap -p -- "$2" | sed -E "s/^trap -- '(.*)' $2\$/\\1/")" "$2"
  fi
  builtin trap ${1+"$@"}
}

実行結果

# 素のtrapは上書きされてしまう
$ cat foo.sh
trap 'echo first' EXIT
trap 'echo second' EXIT

$ bash foo.sh
second


# trapを再定義すると追記が可能
$ cat foo.sh
trap () {
  if ((($# == 3)) && [[ $1 == '--' ]]) || ((($# == 2)) && [[ ${1:0:1} != '-' ]])
  then
    if (($# == 3)) && [[ $1 == '--' ]]
    then
       shift
    fi
    set -- -- "$1 ; $(builtin trap -p -- "$2" | sed -E "s/^trap -- '(.*)' $2\$/\\1/")" "$2"
  fi
  builtin trap ${1+"$@"}
}
trap 'echo first' EXIT
trap 'echo second' EXIT

$ bash foo.sh
second
first