POSIX兼容的方法,如果一个功能是在sh脚本定义(POSIX compliant way to s

2019-07-18 12:22发布

我的正确方法后我看到如果一个函数的定义或没有。 一个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的考虑bash'isms checkbashisms脚本。

试图到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标准的方式来做到这一点?

平原SH请,没有庆典,没有KSH,没有其他的壳,只是普通的SH。 哦,没有实际尝试运行的功能太:)

可能吗?

我已经找到了POSIX兼容的解决方案:

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

现在的问题, 有没有更好的解决办法

Answer 1:

我已经找到了POSIX兼容的方式

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

现在的问题, 有没有更好的解决办法



Answer 2:

虽然我能理解你为什么会这么认为,从其他位置动态拉着你的脚本是没有很大的障碍解析(或“grepping”),它为你喜欢你运行它之前。 这样的事情可以通过多种方式来完成,但是,据我可以做出来,他们都将需要功能完整操作的基本文件描述符。

Bash和它的同类为我们提供通过重定向子壳命令,允许各类管道灵活性这样的透明的文件描述符的便利:

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

但是,正如已经已经提到的,不被POSIX指明的语法设备,所以你必须找到另一种方式。 此外,较短尽管它可能是,这可以是一个有点混乱。 也许有更好的方法来做到这一点,但我想他们至少需要2级或3子shell水平。 (这肯定会很酷做出另外的说明,虽然)。

什么POSIX不指定,然而,这是非常有用的heredoc 。 该heredoc是申报POSIX变量语法类型中罕见的,不仅因为它可以巧妙地跨越多行不逃避组装机,或者是因为它允许外壳替代的清洁定义通过简单地引用它的终结者,但最重要的,因为它描述了一个文件类型句柄。 在这种质量heredoc往往被忽视,也许是因为Bash和合作在很大程度上消除了一段时间的重要性,但是我们应该每隔我们坚持以终止的约定时间想起它heredoc用缩写“文件结束” EOF

为了在脚本文件来拉,编程方式修改它,然后用一个命令解释程序执行它,你将需要一个文件描述符。 您可以读取和写入到/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_


文章来源: POSIX compliant way to see if a function is defined in an sh script
标签: posix sh