Bashシェルスクリプトで関数のコールスタックを取得・出力する

Bash,Linux

はじめに

Bashシェルスクリプトでログを出力する際などに以下のような情報が欲しい場合がありました。

  • 「現在実行中の関数」の名前
  • 「現在実行中の関数」の呼び出し元

これらの情報を取得する方法を説明します。

検証環境

$ uname -moi
x86_64 x86_64 GNU/Linux

$ bash -version | head -n 1
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)

$FUNCNAME 変数を使って「コールスタック」を参照する

$FUNCNAME という配列の変数を参照することで、関数の「コールスタック」情報が取得できます。

サンプルスクリプトを通して、使い方を見ていきましょう。

サンプルスクリプトで確認してみる

以下のような2つのスクリプトを作成して動作を確認してみます。

$ ls
script_main.sh  script_sub.sh
$ cat script_main.sh
#!/usr/bin/env bash

./script_sub.sh

echo

. ./script_sub.sh
$ cat script_sub.sh
#!/usr/bin/env bash

f1 () {
  declare -p FUNCNAME
  echo "${FUNCNAME[@]}"
  echo "0 = ${FUNCNAME[0]}"
  echo "1 = ${FUNCNAME[1]}"
  echo "2 = ${FUNCNAME[2]}"
  echo "3 = ${FUNCNAME[3]}"
}

f2 () {
  f1
}

f2

f1 関数を呼び出すまでの流れは大きく以下のようになっています。

ただし、script_main.sh から script_sub.sh を呼び出す方法として2つの方法を実行しています。

実行結果は以下のようになります。

$ ./script_main.sh
declare -a FUNCNAME='([0]="f1" [1]="f2" [2]="main")'
f1 f2 main
0 = f1
1 = f2
2 = main
3 =

declare -a FUNCNAME='([0]="f1" [1]="f2" [2]="source" [3]="main")'
f1 f2 source main
0 = f1
1 = f2
2 = source
3 = main

$FUNCNAME 変数について

サンプルプログラムからわかったことを整理します。

  • declare -p FUNCNAME コマンドから、変数 $FUNCNAME は配列であることがわかる。
  • ${FUNCNAME[@]} でコールスタックがすべて取得できる
  • ${FUNCNAME[0]} で現在実行中の関数名(ここでは f1 )が取得できる
  • ${FUNCNAME[1]} で呼び出し元の関数名(ここでは f2 )が取得できる
  • ${FUNCNAME[N]}N は添字の最終値)は呼び出し元の main という関数名(?)が取得できる
  • . あるいは source コマンド経由でスクリプトを読み込んだ場合は、 source という中間関数がコールスタックに積まれる

ひとこと

実行中の関数名をログ出力させたい場合などには、以下のような命令が使えます。

$ echo "${FUNCNAME[0]} start" 2>&1

Bash,Linux