Determine if a function exists in bash

2020-01-27 09:20发布

Currently I'm doing some unit tests which are executed from bash. Unit tests are initialized, executed and cleaned up in a bash script. This script usualy contains an init(), execute() and cleanup() functions. But they are not mandatory. I'd like to test if they are or are not defined.

I did this previously by greping and seding the source, but it seemed wrong. Is there a more elegant way to do this?

Edit: The following sniplet works like a charm:

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

13条回答
家丑人穷心不美
2楼-- · 2020-01-27 10:03

From my comment on another answer (which I keep missing when I come back to this page)

$ 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
查看更多
祖国的老花朵
3楼-- · 2020-01-27 10:04

This tells you if it exists, but not that it's a function

fn_exists()
{
  type $1 >/dev/null 2>&1;
}
查看更多
相关推荐>>
4楼-- · 2020-01-27 10:08

Dredging up an old post ... but I recently had use of this and tested both alternatives described with :

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

this generated :

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

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

declare is a helluvalot faster !

查看更多
劳资没心,怎么记你
5楼-- · 2020-01-27 10:12

I think you're looking for the 'type' command. It'll tell you whether something is a function, built-in function, external command, or just not defined. Example:

$ LC_ALL=C type foo
bash: type: foo: not found

$ LC_ALL=C type ls
ls is aliased to `ls --color=auto'

$ which type

$ LC_ALL=C type type
type is a shell builtin

$ LC_ALL=C type -t rvm
function

$ if [ -n "$(LC_ALL=C type -t rvm)" ] && [ "$(LC_ALL=C type -t rvm)" = function ]; then echo rvm is a function; else echo rvm is NOT a function; fi
rvm is a function
查看更多
萌系小妹纸
6楼-- · 2020-01-27 10:12

It is possible to use 'type' without any external commands, but you have to call it twice, so it still ends up about twice as slow as the 'declare' version:

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

Plus this doesn't work in POSIX sh, so it's totally worthless except as trivia!

查看更多
趁早两清
7楼-- · 2020-01-27 10:14

If declare is 10x faster than test, this would seem the obvious answer.

Edit: Below, the -f option is superfluous with BASH, feel free to leave it out. Personally, I have trouble remembering which option does which, so I just use both. -f shows functions, and -F shows function names.

#!/bin/sh

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

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

The "-F" option to declare causes it to only return the name of the found function, rather than the entire contents.

There shouldn't be any measurable performance penalty for using /dev/null, and if it worries you that much:

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

Or combine the two, for your own pointless enjoyment. They both work.

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
查看更多
登录 后发表回答