确定一个函数是否存在于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