目前我正在做一些从bash执行的单元测试。单元测试在bash脚本中初始化、执行和清理。该脚本通常包含init()、execute()和cleanup()函数。但它们不是强制性的。我想测试它们是否有定义。

我以前通过greping和seding源代码做到了这一点,但这似乎是错误的。还有更优雅的方式吗?

编辑:下面这句话很有魔力:

fn_exists()
{
    LC_ALL=C type $1 | grep -q 'shell function'
}

当前回答

我会将其改进为:

fn_exists()
{
    type $1 2>/dev/null | grep -q 'is a function'
}

像这样使用它:

fn_exists test_function
if [ $? -eq 0 ]; then
    echo 'Function exists!'
else
    echo 'Function does not exist...'
fi

其他回答

这告诉你它是否存在,但不是说它是一个函数

fn_exists()
{
  type $1 >/dev/null 2>&1;
}

它可以归结为使用“declare”来检查输出或退出代码。

输出方式:

isFunction() { [[ "$(declare -Ff "$1")" ]]; }

用法:

isFunction some_name && echo yes || echo no

然而,如果内存有用,重定向到null比输出替换更快(说到这里,可怕的过时的' cmd '方法应该被摒弃,取而代之的是$(cmd)。)由于declare在找到/未找到时返回true/false,并且函数返回函数中最后一个命令的退出码,因此通常不需要显式返回,并且由于检查错误代码比检查字符串值(甚至是空字符串)更快:

退出状态样式:

isFunction() { declare -Ff "$1" >/dev/null; }

这可能是你能得到的最简洁和最温和的说法了。

我会将其改进为:

fn_exists()
{
    type $1 2>/dev/null | grep -q 'is a function'
}

像这样使用它:

fn_exists test_function
if [ $? -eq 0 ]; then
    echo 'Function exists!'
else
    echo 'Function does not exist...'
fi

挖掘一根旧柱子……但我最近使用了这个方法,并测试了以下两种替代方法:

test_declare () {
    a () { echo 'a' ;}

    declare -f a > /dev/null
}

test_type () {
    a () { echo 'a' ;}
    type a | grep -q 'is a function'
}

echo 'declare'
time for i in $(seq 1 1000); do test_declare; done
echo 'type'
time for i in $(seq 1 100); do test_type; done

这产生了:

real    0m0.064s
user    0m0.040s
sys     0m0.020s
type

real    0m2.769s
user    0m1.620s
sys     0m1.130s

声明要快得多!

如果declare比test快10倍,这似乎是显而易见的答案。

编辑:下面,-f选项在BASH中是多余的,可以省略它。就我个人而言,我很难记住哪个选项能做哪个,所以我两种都用。-f显示函数,-f显示函数名。

#!/bin/sh

function_exists() {
    declare -f -F $1 > /dev/null
    return $?
}

function_exists function_name && echo Exists || echo No such function

要声明的“-F”选项导致它只返回找到的函数的名称,而不是整个内容。

使用/dev/null不应该有任何可衡量的性能损失,如果您如此担心:

fname=`declare -f -F $1`
[ -n "$fname" ]    && echo Declare -f says $fname exists || echo Declare -f says $1 does not exist

或者把两者结合起来,只为你自己毫无意义的享受。它们都有效。

fname=`declare -f -F $1`
errorlevel=$?
(( ! errorlevel )) && echo Errorlevel says $1 exists     || echo Errorlevel says $1 does not exist
[ -n "$fname" ]    && echo Declare -f says $fname exists || echo Declare -f says $1 does not exist