bashのトラップハンドラにローカル変数を渡す方法

bashのトラップハンドラにローカル変数を渡す方法

bash関数で宣言されたローカル変数は、呼び出された関数には表示されますが、トラップハンドラには表示されません。

#!/bin/bash

function exit_handler() {
  echo "Exit handler: ${device_name}"
}

function other() {
  echo "Other: ${device_name}"
}

function do_something() {
  local device_name="abc"
  trap exit_handler EXIT
  other
}

do_something

出力:

$ bash test.sh 
Other: abc
Error handler: 

ローカル変数の値をトラップハンドラに渡す最善の方法は何ですか?変数がすぐに拡張されるのか、関数の末尾で拡張されるのか(後者がローカル変数に対して可能でない場合)は、私にとっては重要ではありません。

私が試したこと:

  1. 変数を削除してグローバル変数にしますlocal。この方法は有効ですが、グローバルネームスペースを汚染したくないので、このソリューションは気に入らません。

  2. 変数をハンドラに直接渡します。

    function exit_handler() {
      local device_name="${1}"
      echo "Error handler: ${device_name}"
    }
    
    function do_something() {
      local device_name="abc"
      trap exit_handler "${device_name}" EXIT
    }
    

    これは機能しません(invalid signal specification)。値がシグナル名として解釈されると仮定します。信号名からコマンドを分離する方法はありますか?

  3. トラップコマンドを一重引用符で囲みます(これは次の理由による)。shellcheck):

    function exit_handler() {
      local device_name="${1}"
      echo "Exit handler: ${device_name}"
    }
    
    function do_something() {
      local device_name="abc"
      trap 'exit_handler "${device_name}"' EXIT
    }
    

    しかし、これはまだ終了ハンドラから空の出力を提供します。だから、ローカル変数が十分に長く生きていないかもしれないと思います。

答え1

解決策3.非常に近い。関数のコンテキストで変数を評価する必要があります。do_something

更新された例は次のとおりです。

#!/bin/bash

function exit_handler() {
  local device_name="${1}"
  echo "Exit handler: ${device_name}"
}

function other() {
  echo "Other: ${device_name}"
}

function do_something() {
  local device_name="abc"
  trap "exit_handler '${device_name}'" EXIT
  other
}

do_something

関連情報