Search code examples
bashclosureslexical-closures

Closures get parent function name


Bash is “kind of function programming language” it dose not have classes. I managed to use encapsulation with Closures, but I want also to do some introspection to find also docker_ parent/super/base function (If you know add comments to define this correctly).

I managed this but with a dirty hack super=${FUNCNAME}. Is there any solution to use kind of PARENT_FUNCNAME? I have such file docker_.sh:

#!/usr/bin/env bash
function docker_ {
    local super=${FUNCNAME}
    function hello {
        echo "INFO" "do ${super}${FUNCNAME}"
    }
    function install {
        echo "INFO" "do ${super}${FUNCNAME}"
        #sudo curl -sSL https://get.docker.com/ | sh || exit 1
    }
    function run {
        echo "INFO" "do ${super}${FUNCNAME}"
        #docker run -d -p 3306:3306 ${DOCKER_IMAGE_NAME} /docker.sh run_mysql
    }
    ${@}
}
${@}

Got some results:

$ ./docker_.sh docker_ hello
INFO do docker_hello

$ ./docker_.sh docker_ run
INFO do docker_run

$ ./docker_.sh docker_ install
INFO do docker_install

Solved

use

${FUNCNAME[1]}
${FUNCNAME[@]:0:${#FUNCNAME[@]}-1} get all list beside main

code:

#!/usr/bin/env bash
function docker_ {
    function hello {
        echo "INFO" "do ${FUNCNAME[1]} ${FUNCNAME}"
    }
    function install {
        echo "INFO" "do > ${FUNCNAME[@]:0:${#FUNCNAME[@]}-1} "
        #sudo curl -sSL https://get.docker.com/ | sh || exit 1
    }
    function run {
        echo "INFO" "do > ${FUNCNAME[@]:0:${#FUNCNAME[@]}-1} "
        #docker run -d -p 3306:3306 ${DOCKER_IMAGE_NAME} /docker.sh run_mysql
    }
    ${@}
}
${@}

Got some results:

    ➜ ./docker_.sh docker_ hello  
    INFO do docker_ hello
    ➜ ./docker_.sh docker_ install
    INFO do > install docker_ 
    ➜ ./docker_.sh docker_ run    
    INFO do > run docker_ 

Solution

  • Bash really isn't a functional programming language. To start with, functions are not first-class objects; you cannot pass a function around. You can pass around the name of a function, but it's just a name; if the name is given a new value, then the old value is lost.

    Bash does not have lexical scoping: bash scoping is dynamic. The local command is a command, like any other command. It is not syntactic. If it is not executed, the name is not made local. For example:

    f() {
      if [[ $1 == local ]]; then local myvar=local; fi
      myvar=changed
    }
    
    $ var=original
    $ f local
    $ echo $myvar
    original
    $ f global
    $ echo $myvar
    changed
    

    And bash does not have closures. You can define a function inside a function, but the function so defined does not carry the scope with it.

    $ g() {
    >   local myvar=inner
    >    f() { echo $myvar; }
    >    f
    > }
    $ myvar=outer
    $ g
    inner
    $ f
    outer
    $ h() { local myvar=inside_h; f; }
    $ h
    inside_h
    $ f
    outer