我正在寻找是否定义函数的正确方法。符合POSIX标准的方式。
__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
}
根据debian的checkbashisms脚本,以上所有内容都被视为bash'isms。
尝试grep脚本也不行。例如:
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
不起作用,因为脚本也应该像:
wget --no-check-certificate -O - http://URL_TO_SCRIPT | sudo sh
那么,正确的POSIX兼容方法是什么?
请原谅,没有bash,没有ksh,没有其他shell,只是简单的sh。哦,并且实际上没有尝试运行该功能:)有可能吗?
if [ "$(command -v $FUNC_NAME)x" != "x" ]; then
echo " * INFO: Found function $FUNC_NAME"
return 0
fi
现在的问题,有更好的解决方案吗??
答案 0 :(得分:1)
if [ "$(command -v $FUNC_NAME)x" != "x" ]; then
echo " * INFO: Found function $FUNC_NAME"
return 0
fi
现在的问题,有更好的解决方案吗??
答案 1 :(得分:0)
虽然我可以理解你为什么这么认为,但是在你运行它之前动态地从另一个位置拉动你的脚本并不是解析(或“grepping”)它的绝佳障碍。这样的事情可以用几种方式完成,但是,据我所知,它们都需要一个基本的文件描述符来完成功能上的完整操作。
Bash及其同类提供透明文件描述符的便利,通过重定向的子shell命令,允许各种管道灵活性,如下所示:
eval "$(wget --no-check-certificate -O - ${_URL} | tee \
>(read func; echo '_FUNC='"$(grep -Eo '^[^ |^#]*()' <(echo "${func}"))") \
| sudo sh)"
但是,正如已经提到的那样,POSIX没有指定这样的语法设备,因此您必须找到另一种方法。而且,尽管可能更短,但这可能有点令人困惑。可能有更好的方法可以做到这一点,但我想他们至少需要2或3个子壳级别。 (不过,以其他方式显示确实很酷。)
然而,POSIX指定的是非常有用的heredoc
。 heredoc
在声明的POSIX变量语法类型中很少见,不仅因为它可以整齐地跨越多行而没有转义符号,或者因为它允许通过简单引用它的终结符来清晰定义shell替换,但最重要的是因为它描述了文件类型句柄。 heredoc
的这种质量经常被忽视,也许是因为Bash和co在很长一段时间内已经基本消除了它的重要性,但每当我们遵守终止heredoc
的惯例时我们都应该提醒它。使用“文件结尾”首字母缩写EOF
。
为了引入脚本文件,以编程方式修改它,然后使用shell解释器执行它,您将需要一个文件描述符。当然,你可以读写/tmp/
以允许这样做,但我通常会尽量避免这种情况,因为它只是感觉马虎。如果必须的话,你甚至可以改写自己,但这可能不是最好的习惯。但是,如果你找到了真正的原因,最安全的方法可能是在脚本开头的函数中定义重写代码,并且只在最后调用它,这样你才能确保整个文件已经完全加载进入记忆。像这样:
_rewrite_me() {printf %s "${1}" > ${0} && exec ${0}}
#SHELL CODE
#MORE
_NEW_ME="$(printf %s "${_MORE_SHELL_CODE}" | cat <${0})"
rewrite_me ${_NEW_ME}
尽管如此,我最喜欢heredoc
,我认为在这种情况下它是缺失的拼图。以下是使用heredoc
简短而简单的,应完全符合POSIX标准,并且应该很容易适应您的目的,我希望:
#!/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_