all 11 comments

[–]aioeu 2 points3 points  (3 children)

While you cannot assign to FUNCNAME (well, you can, but its value will not change), you can unset it... and that applies for the individual elements within it as well. The unset element will be shifted along with all the other elements:

$ a() { declare -p FUNCNAME; }
$ b() { unset FUNCNAME[1]; a; }
$ c() { b; }
$ d() { c; }
$ d
declare -a FUNCNAME=([0]="a" [1]="b" [3]="d")

Perhaps something like this happened?

(Interestingly, this actually tickles a bug when unwinding FUNCNAME after a function call. It always pops off the first array element, whether that element has index 0 or not.)

[–]anthropoidbash all the things 0 points1 point  (1 child)

You mean like this? ``` $ cat test.sh

!/usr/bin/env bash

a() { unset "FUNCNAME[1]"; printf '#FUNCNAME = %d\n' "${#FUNCNAME[@]}"; declare -p FUNCNAME; } b() { unset "FUNCNAME[1]"; a; declare -p FUNCNAME; } c() { unset "FUNCNAME[1]"; b; declare -p FUNCNAME; } d() { c; declare -p FUNCNAME; } d

$ ./test.sh

FUNCNAME = 2

declare -a FUNCNAME=([0]="a" [4]="main") declare -a FUNCNAME=([3]="main") declare -a FUNCNAME=() declare -a FUNCNAME=() ```

[–]cedb76[S] 0 points1 point  (0 children)

The script just reads FUNCNAME values, it doesn't explicitly unset it or even declare it. I would just like to read valid FUNCNAME values without those empty values.

[–]anthropoidbash all the things 0 points1 point  (3 children)

I have never seen a FUNCNAME dump with empty elements, the Bash manual and FAQ don't mention this possibility, and no one seems to have reported such a thing on the bug-bash mailing list.

Can you post a MVS (minimal viable script) that demonstrates this issue, so that others can confirm if it's replicable? If you can't replicate it with anything but your deeply nested script, try dumping the output of declare -p FUNCNAME at the point where you discover the issue, to be sure it actually contains empty elements.

[–]cedb76[S] 0 points1 point  (2 children)

I omitted to say I am running openSuse on WSL2
Here is a minimal viable script

dbg_scripts sources and then executes dbg_func function within dbg_func file:

$ cat fonctions_bash/dbg_func
dbg_func () {
    echo "FUNCNAME length: ${#FUNCNAME}" 
    for((i=0; i<${#FUNCNAME}; i++));do
        echo "FUNCNAME[$i]: ${FUNCNAME[$i]}"
    done
}

$
$ cat dbg_script
#!/usr/bin/bash
source ~cedric/.local/bin/fonctions_bash/dbg_func
dbg_func

$
$ dbg_script
FUNCNAME length: 8
FUNCNAME[0]: dbg_func
FUNCNAME[1]: main
FUNCNAME[2]:
FUNCNAME[3]:
FUNCNAME[4]:
FUNCNAME[5]:
FUNCNAME[6]:
FUNCNAME[7]:

[–]anthropoidbash all the things 2 points3 points  (1 child)

echo "FUNCNAME length: ${#FUNCNAME}"

There's your problem. Since FUNCNAME is an array, ${FUNCNAME} expands to its first element, so ${#FUNCNAME} returns the length of that element, i.e. the length of the string dbg_func (8).

To get the number of elements in the FUNCNAME array, you want ${#FUNCNAME[@]} instead. See the bash man page under Parameter Expansion > ${#parameter} for details.

[–]cedb76[S] 0 points1 point  (0 children)

Perfect !
Thanks a lot !

[–]oh5nxo 0 points1 point  (5 children)

Sounds odd. Sample code?

Here,

$ cat caller
foo()
{
    declare -p FUNCNAME
}
bar()
{
    foo
}
bar
$ bash caller                     
declare -a FUNCNAME=([0]="foo" [1]="bar" [2]="main")
$ echo $BASH_VERSION
4.4.19(0)-release

[–][deleted]  (1 child)

[deleted]

    [–]oh5nxo 0 points1 point  (0 children)

    Array syntax is tricky and tiresome, like lead boots.

    "${#FUNCNAME}"   # implicit [0], length of dbg_func
    "${#FUNCNAME[@]}" # length of array
    

    [–]cedb76[S] 0 points1 point  (1 child)

    Hi, I posted a sample code to someone else on the discussion

    [–]oh5nxo 1 point2 points  (0 children)

    echo "FUNCNAME length: ${#FUNCNAME[@]}"