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)
if [ "${DISTRO_NAME_L}" = "centos" ]; then
if typeset -f $FUNC_NAME &>/dev/null ; then
echo " * INFO: Found function $FUNC_NAME"
return 0
fi
# Try POSIXLY_CORRECT or not
elif test -n "${POSIXLY_CORRECT+yes}"; then
if typeset -f ${FUNC_NAME} >/dev/null 2>&1 ; then
echo " * INFO: Found function $FUNC_NAME"
return 0
fi
else
# Arch linux seems to fall here
if $( type ${FUNC_NAME} >/dev/null 2>&1 ) ; then
echo " * INFO: Found function $FUNC_NAME"
return 0
fi
echo " * INFO: $FUNC_NAME not found...."
return 1
}
All of the above are considered bash'isms according to debian's checkbashisms script.
Trying to grep the script is also not ok. for example:
if [ "$(grep $FUNC_NAME $(dirname $0)/$(basename $0))x" != "x" ]; then
# This is really ugly and counter producing but it was, so far, the
# only way we could have a POSIX compliant method to find if a function
# is defined within this script.
echo " * INFO: Found function $FUNC_NAME"
return 0
fi
won't work because the script is also supposed to work like:
wget --no-check-certificate -O - http://URL_TO_SCRIPT | sudo sh
So, what's the proper, POSIX compliant way to do this?
Plain sh please, no bash, no ksh, no other shell, just plain sh. Oh, and without actually trying to run the function too :)
Is it possible?
I have found a POSIX compliant solution:
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?
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:
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
. Theheredoc
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 theheredoc
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 aheredoc
with the "end of file" acronymEOF
.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: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 theheredoc
, should be fully POSIX compliant, and should easily be adapted to your purposes, I hope:I have found a POSIX compliant way
The question now, Is there a better solution?