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

时间:2022-11-23 09:26:37

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.

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

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

我之前做过的方法是使用greping和seding源文件,但这似乎是错误的。有更优雅的方式来做这件事吗?

Edit: The following sniplet works like a charm:

编辑:下面的sniplet就像一个咒语:

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

13 个解决方案

#1


151  

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:

我想你是在找‘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

#2


56  

$ g() { return; }
$ declare -f g > /dev/null; echo $?
0
$ declare -f j > /dev/null; echo $?
1

#3


31  

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

如果声明比测试快10倍,这似乎是显而易见的答案。

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.

编辑:下面,-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

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

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

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

使用/dev/null不应该有任何可度量的性能惩罚,如果它让您非常担心:

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

#4


15  

Borrowing from other solutions and comments, I came up with this:

从其他的解决方案和评论中,我想到了:

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' ]
}

Used as ...

用作……

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

It checks if the given argument is a function, and avoids redirections and other grepping.

它检查给定的参数是否为函数,并避免重定向和其他错误。

#5


8  

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 !

声明是一个helluvalot快!

#6


5  

It boils down to using 'declare' to either check the output or exit code.

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

Output style:

输出方式:

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

Usage:

用法:

isFunction some_name && echo yes || echo no

However, if memory serves, redirecting to null is faster than output substitution (speaking of, the awful and out-dated `cmd` method should be banished and $(cmd) used instead.) And since declare returns true/false if found/not found, and functions return the exit code of the last command in the function so an explicit return is usually not necessary, and since checking the error code is faster than checking a string value (even a null string):

但是,如果内存服务,重定向到null比输出替换快(说到,糟糕的和过时的“cmd”方法应该被禁用,而$(cmd)取而代之。)并且,由于声明返回true/false,如果找到/未找到,函数返回函数中最后一个命令的退出代码,所以显式返回通常是不必要的,并且检查错误代码的速度比检查字符串值(甚至空字符串)要快:

Exit status style:

退出状态风格:

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

That's probably about as succinct and benign as you can get.

这可能是你能得到的最简洁、最友好的。

#7


3  

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

update

更新

isFunc () 
{ 
    [[ $(type -t $1) == function ]]
}

$ isFunc isFunc
$ echo $?
0
$ isFunc dfgjhgljhk
$ echo $?
1
$ isFunc psgrep && echo yay
yay
$

#8


3  

Testing speed of different solutions

测试不同解决方案的速度

#!/bin/bash

f () {
echo 'This is a test function.'
echo 'This has more than one command.'
return 0
}

test_declare () {
    declare -f f > /dev/null
}

test_declare2 () {
    declare -F f > /dev/null
}

test_type () {
    type -t f | grep -q 'function'
}

test_type2 () {
    local var=$(type -t f)
    [[ "${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 -f f
post='(f unset)'
done

outputs e.g.:

例如:输出

declare -f

声明- f

real 0m0.037s user 0m0.024s sys 0m0.012s

用户0m0.024s系统0m0.012s

declare -F

声明- f

real 0m0.030s user 0m0.020s sys 0m0.008s

用户0m0.020系统0m0.008s

type with grep

类型与grep

real 0m1.772s user 0m0.084s sys 0m0.340s

real 0m1.772s用户0m0.084s系统0m0.340s

type with var

类型与var

real 0m0.770s user 0m0.096s sys 0m0.160s

real 0m0.70用户0m0.096s系统0m0.160s

declare -f (f unset)

声明- f(f设置)

real 0m0.031s user 0m0.028s sys 0m0.000s

真正的0m0.031s用户0m0.028s系统0m0.000s

declare -F (f unset)

声明- f(f设置)

real 0m0.031s user 0m0.020s sys 0m0.008s

真正的0m0.031s用户0m0.020s系统0m0.008s

type with grep (f unset)

输入grep (f未设置)

real 0m1.859s user 0m0.100s sys 0m0.348s

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

type with var (f unset)

类型为var (f未设置)

real 0m0.683s user 0m0.092s sys 0m0.160s

用户0m0.092s系统0m0.160s

So declare -F f && echo function f exists. || echo function f does not exist. seems to be the best solution.

因此,声明-F && & echo函数f存在。||回波函数f不存在。似乎是最好的解决办法。

#9


2  

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

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

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

#10


2  

I particularly liked solution from Grégory Joseph

我特别喜欢格雷戈里·约瑟夫的解决方案。

But I've modified it a little bit to overcome "double quote ugly trick":

但是我对它做了一点修改,以克服“双重引用的丑陋把戏”:

function is_executable()
{
    typeset TYPE_RESULT="`type -t $1`"

    if [ "$TYPE_RESULT" == 'function' ]; then
        return 0
    else
        return 1
    fi
}

#11


1  

I would improve it to:

我会把它改进为:

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

And use it like this:

像这样使用它:

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

#12


0  

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:

不需要任何外部命令就可以使用“type”,但您必须调用它两次,因此它最终的速度仍是“declare”版本的两倍:

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!

另外,这个在POSIX sh中不起作用,所以它完全没有价值,除了作为琐事!

#13


0  

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

#1


151  

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:

我想你是在找‘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

#2


56  

$ g() { return; }
$ declare -f g > /dev/null; echo $?
0
$ declare -f j > /dev/null; echo $?
1

#3


31  

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

如果声明比测试快10倍,这似乎是显而易见的答案。

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.

编辑:下面,-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

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

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

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

使用/dev/null不应该有任何可度量的性能惩罚,如果它让您非常担心:

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

#4


15  

Borrowing from other solutions and comments, I came up with this:

从其他的解决方案和评论中,我想到了:

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' ]
}

Used as ...

用作……

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

It checks if the given argument is a function, and avoids redirections and other grepping.

它检查给定的参数是否为函数,并避免重定向和其他错误。

#5


8  

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 !

声明是一个helluvalot快!

#6


5  

It boils down to using 'declare' to either check the output or exit code.

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

Output style:

输出方式:

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

Usage:

用法:

isFunction some_name && echo yes || echo no

However, if memory serves, redirecting to null is faster than output substitution (speaking of, the awful and out-dated `cmd` method should be banished and $(cmd) used instead.) And since declare returns true/false if found/not found, and functions return the exit code of the last command in the function so an explicit return is usually not necessary, and since checking the error code is faster than checking a string value (even a null string):

但是,如果内存服务,重定向到null比输出替换快(说到,糟糕的和过时的“cmd”方法应该被禁用,而$(cmd)取而代之。)并且,由于声明返回true/false,如果找到/未找到,函数返回函数中最后一个命令的退出代码,所以显式返回通常是不必要的,并且检查错误代码的速度比检查字符串值(甚至空字符串)要快:

Exit status style:

退出状态风格:

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

That's probably about as succinct and benign as you can get.

这可能是你能得到的最简洁、最友好的。

#7


3  

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

update

更新

isFunc () 
{ 
    [[ $(type -t $1) == function ]]
}

$ isFunc isFunc
$ echo $?
0
$ isFunc dfgjhgljhk
$ echo $?
1
$ isFunc psgrep && echo yay
yay
$

#8


3  

Testing speed of different solutions

测试不同解决方案的速度

#!/bin/bash

f () {
echo 'This is a test function.'
echo 'This has more than one command.'
return 0
}

test_declare () {
    declare -f f > /dev/null
}

test_declare2 () {
    declare -F f > /dev/null
}

test_type () {
    type -t f | grep -q 'function'
}

test_type2 () {
    local var=$(type -t f)
    [[ "${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 -f f
post='(f unset)'
done

outputs e.g.:

例如:输出

declare -f

声明- f

real 0m0.037s user 0m0.024s sys 0m0.012s

用户0m0.024s系统0m0.012s

declare -F

声明- f

real 0m0.030s user 0m0.020s sys 0m0.008s

用户0m0.020系统0m0.008s

type with grep

类型与grep

real 0m1.772s user 0m0.084s sys 0m0.340s

real 0m1.772s用户0m0.084s系统0m0.340s

type with var

类型与var

real 0m0.770s user 0m0.096s sys 0m0.160s

real 0m0.70用户0m0.096s系统0m0.160s

declare -f (f unset)

声明- f(f设置)

real 0m0.031s user 0m0.028s sys 0m0.000s

真正的0m0.031s用户0m0.028s系统0m0.000s

declare -F (f unset)

声明- f(f设置)

real 0m0.031s user 0m0.020s sys 0m0.008s

真正的0m0.031s用户0m0.020s系统0m0.008s

type with grep (f unset)

输入grep (f未设置)

real 0m1.859s user 0m0.100s sys 0m0.348s

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

type with var (f unset)

类型为var (f未设置)

real 0m0.683s user 0m0.092s sys 0m0.160s

用户0m0.092s系统0m0.160s

So declare -F f && echo function f exists. || echo function f does not exist. seems to be the best solution.

因此,声明-F && & echo函数f存在。||回波函数f不存在。似乎是最好的解决办法。

#9


2  

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

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

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

#10


2  

I particularly liked solution from Grégory Joseph

我特别喜欢格雷戈里·约瑟夫的解决方案。

But I've modified it a little bit to overcome "double quote ugly trick":

但是我对它做了一点修改,以克服“双重引用的丑陋把戏”:

function is_executable()
{
    typeset TYPE_RESULT="`type -t $1`"

    if [ "$TYPE_RESULT" == 'function' ]; then
        return 0
    else
        return 1
    fi
}

#11


1  

I would improve it to:

我会把它改进为:

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

And use it like this:

像这样使用它:

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

#12


0  

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:

不需要任何外部命令就可以使用“type”,但您必须调用它两次,因此它最终的速度仍是“declare”版本的两倍:

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!

另外,这个在POSIX sh中不起作用,所以它完全没有价值,除了作为琐事!

#13


0  

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