bash でスタックトレース

bash には perl の confess 相当のサブルーチンがありません。しかし実装することができます。

#!bash
source carp.sh

foo() {
    confess "something wrong"
    echo "this line will not be executed."
}
bar() {
    foo
}
baz() {
    bar
}

baz
exit
$ sh stacktrace.sh 
something wrong at stacktrace.sh line 5
	foo() called at stacktrace.sh line 9
	bar() called at stacktrace.sh line 12
	baz() called at stacktrace.sh line 15
$

carp.sh の中身はこちら。

#!bash
confess() {
    local mess max i line src

    mess=$1
    let max=${#BASH_LINENO[@]}-1

    line=${BASH_LINENO[0]}
    src=${BASH_SOURCE[1]}
    echo "$mess at $src line $line" >&2

    i=1
    while [ $i -lt $max ]; do
        line=${BASH_LINENO[$i]}
        src=${BASH_SOURCE[`expr $i + 1`]}
        echo "	${FUNCNAME[$i]}() called" \
            "at $src line $line" >&2
        let i=$i+1
    done

    exit 255
}

BASH_SOURCE と FUNCNAME の要素番号が1個ずれていることに気づかず、間違ったコードを乗せていた。訂正済み。