POSIX compliant way to see if a function is defined in an sh script

后端 未结 2 1757
盖世英雄少女心
盖世英雄少女心 2021-01-07 04:02

I\'m after THE proper way to see if a function is defined or not. A POSIX compliant way.

__function_defined() {
    FUNC_NAME=$1
    d=$(declare -f $FUNCNAME         


        
相关标签:
2条回答
  • 2021-01-07 04:22

    While I can understand why you might think so, dynamically pulling your script from another location is no great barrier to parsing (or "grepping") it as you like before you run it. Such a thing can be accomplished in several ways, but, as far as I can make out, they will all require a basic file descriptor for functionally complete operation.

    Bash and its ilk provide us the convenience of transparent file descriptors via redirected sub-shelled commands which allow for all kinds of pipeline flexibility like this:

    eval "$(wget --no-check-certificate -O - ${_URL} | tee \
        >(read func; echo '_FUNC='"$(grep -Eo '^[^ |^#]*()' <(echo "${func}"))") \
        | sudo sh)" 
    

    But, as has been mentioned already, such syntax devices are not specified by POSIX, and so you must find another way. Also, shorter though it may be, that can be a little confusing. Probably there are much better ways to do that, but I imagine them requiring 2 or 3 subshell levels at least. (It sure would be cool to be shown otherwise, though.)

    What POSIX does specify, however, is the very useful heredoc. The heredoc is rare among declarable POSIX variable syntax types not only because it can neatly span multiple lines without escape kludges, or because it allows for clean definition of shell substitution by simply quoting its terminator, but most importantly because it describes a file type handle. This quality of the heredoc is often overlooked, perhaps because Bash and co have largely obviated its importance for some time now, but we should be reminded of it every time we adhere to the convention of terminating a heredoc with the "end of file" acronym EOF.

    In order to pull in a script file, modify it programmatically, and then execute it with a shell interpreter you will need a file descriptor. You can read and write to /tmp/ to allow for this, of course, but I generally try to avoid that because it just feels sloppy. You could even, perhaps, rewrite yourself if you must, but it is probably not the best habit to get into. If you find real cause to do this, however, the safest way is probably to define the rewrite code in a function at the beginning of your script and only call it at the very end so you can be sure the entire file has been fully loaded into memory. Something like this:

    _rewrite_me() {printf %s "${1}" > ${0} && exec ${0}} 
    #SHELL CODE
    #MORE 
    _NEW_ME="$(printf %s "${_MORE_SHELL_CODE}" | cat <${0})"
    rewrite_me ${_NEW_ME}
    

    Still, I like the heredoc best, and I think it is the missing puzzle piece in this case. The following is made short and simple with use of the heredoc, should be fully POSIX compliant, and should easily be adapted to your purposes, I hope:

    #!/bin/sh
    _URL='http://URL/TO/SCRIPT'
    
    _SCRIPT="$(wget --no-check-certificate -O - ${_URL} |\
        grep -Ev '^#!')" 
    
    _FUNC="$(sed -n 's:^\([^ |^#|^=]*\)().*{.*$:\1:p' <<_EOF_)"
    ${_SCRIPT}
    _EOF_
    echo "${_FUNC}"
    
    sh <<_EOF_
    ${_SCRIPT}
    _EOF_
    
    0 讨论(0)
  • 2021-01-07 04:24

    I have found a POSIX compliant way

    if [ "$(command -v $FUNC_NAME)x" != "x" ]; then
        echo " * INFO: Found function $FUNC_NAME"
        return 0
    fi
    

    The question now, Is there a better solution?

    0 讨论(0)
提交回复
热议问题