确定一个函数是否存在于bash中

目前我正在做一些从bash执行的unit testing。 unit testing被初始化,执行并在bash脚本中清理。 这个脚本通常包含一个init(),execute()和cleanup()函数。 但他们不是强制性的。 我想testing他们是否定义。

以前我是通过greping和seding来源来做到这一点的,但是这看起来不对。 有没有更优雅的方式来做到这一点?

编辑:下面的sniplet就像一个魅力:

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

我想你正在寻找'type'命令。 它会告诉你是否有东西是一个函数,内置函数,外部命令,或只是没有定义。 例:

 $ type foo bash: type: foo: not found $ type ls ls is aliased to `ls --color=auto' $ which type $ type type type is a shell builtin $ type -t rvm function $ if [ -n "$(type -t rvm)" ] && [ "$(type -t rvm)" = function ]; then echo rvm is a function; else echo rvm is NOT a function; fi rvm is a function 
 $ g() { return; } $ declare -fg > /dev/null; echo $? 0 $ declare -fj > /dev/null; echo $? 1 

如果声明比testing快10倍,这似乎是一个明显的答案。

编辑:下面, -f选项对于BASH来说是多余的,随时放弃。 就我个人而言,我无法记住哪个选项会执行哪个操作,所以我只是使用这两个选项。 -f显示function, -F显示function名称。

 #!/bin/sh function_exists() { declare -f -F $1 > /dev/null return $? } function_exists function_name && echo Exists || echo No such function 

声明的“-F”选项使其仅返回find的函数的名称,而不是整个内容。

对于使用/ 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 

从其他解决scheme和评论借用,我想出了这个:

 fn_exists() { # appended double quote is an ugly trick to make sure we do get a string -- if $1 is not a known command, type does not output anything [ `type -t $1`"" == 'function' ] } 

用作…

 if ! fn_exists $FN; then echo "Hey, $FN does not exist ! Duh." exit 2 fi 

它检查给定的参数是否是一个函数,并避免redirect和其他grepping。

疏浚旧的职位…但我最近有这个使用和testing两个替代描述与:

 test_declare () { a () { echo 'a' ;} declare -fa > /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 

申报是一个helluvalot更快!

归结为使用“声明”来检查输出或退出代码。

输出风格:

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

用法:

 isFunction some_name && echo yes || echo no 

然而,如果内存服务,redirect到null比输出replace要快(说起来,糟糕和过时的`cmd`方法应该被放弃,而使用$(cmd))。因为declare返回true / false,如果find/没有find,函数返回函数中最后一个命令的退出代码,所以显式返回通常是不必要的,因为检查错误代码比检查string值(甚至是空string)更快:

退出状态风格:

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

这可能就像你所能得到的一样简洁和善意。

 fn_exists() { [[ $(type -t $1) == function ]] && return 0 } 

更新

 isFunc () { [[ $(type -t $1) == function ]] } $ isFunc isFunc $ echo $? 0 $ isFunc dfgjhgljhk $ echo $? 1 $ isFunc psgrep && echo yay yay $ 

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

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

我特别喜欢GrégoryJoseph的解决scheme

但我已经修改了一点点,以克服“双引号丑陋的伎俩”:

 function is_executable() { typeset TYPE_RESULT="`type -t $1`" if [ "$TYPE_RESULT" == 'function' ]; then return 0 else return 1 fi } 

我会改进它:

 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 

testing不同解决scheme的速度

 #!/bin/bash f () { echo 'This is a test function.' echo 'This has more than one command.' return 0 } test_declare () { declare -ff > /dev/null } test_declare2 () { declare -F f > /dev/null } test_type () { type -tf | grep -q 'function' } test_type2 () { local var=$(type -tf) [[ "${var-}" = function ]] } post= for j in 1 2; do echo echo 'declare -f' $post time for i in $(seq 1 1000); do test_declare; done echo echo 'declare -F' $post time for i in $(seq 1 1000); do test_declare2; done echo echo 'type with grep' $post time for i in $(seq 1 1000); do test_type; done echo echo 'type with var' $post time for i in $(seq 1 1000); do test_type2; done unset -ff post='(f unset)' done 

输出例如:

声明-f

实际0m0.037s用户0m0.024s sys 0m0.012s

申报-F

实际0m0.030s用户0m0.020s系统0m0.008s

用grep键入

实际0m1.772s用户0m0.084s sys 0m0.340s

键入var

实际0m0.770s用户0m0.096s系统0m0.160s

声明-f(f unset)

实际0m0.031s用户0m0.028s系统0m0.000s

声明-F(f unset)

实际0m0.031s用户0m0.020s系统0m0.008s

键入grep(f unset)

实际0m1.859s用户0m0.100s系统0m0.348s

键入var(f unset)

实际0m0.683s用户0m0.092s系统0m0.160s

所以declare -F f && echo function f exists. || echo function f does not exist. declare -F f && echo function f exists. || echo function f does not exist. 似乎是最好的解决scheme。

可以在不使用外部命令的情况下使用'type',但是必须调用它两次,所以它的结果大约是'declare'版本的两倍:

 test_function () { ! type -f $1 >/dev/null 2>&1 && type -t $1 >/dev/null 2>&1 } 

再加上这在POSIX中不起作用,所以除了作为琐事之外它是毫无价值的!

从我对另一个答案的评论(当我回到这个页面时,我一直想念)

 $ fn_exists() { test x$(type -t $1) = xfunction; } $ fn_exists func1 && echo yes || echo no no $ func1() { echo hi from func1; } $ func1 hi from func1 $ fn_exists func1 && echo yes || echo no yes