从Bash脚本中检查函数是否存在

21

如何判断bash脚本中函数是否已定义?

我正在尝试使我的.bash_login脚本在各个系统间可移植,因此我想添加逻辑仅在该函数存在时调用它。

我希望仅当该系统上存在__git_ps1()函数时才将其添加到PS1中。该函数通常在git-completion.bash(随git源代码提供)或其中一个端口/ apt安装的bash补全脚本中定义。

9个回答

20

我知道这是一个老问题,但其他答案都没有像我想的那样简单。这里使用type -t(如Chen Levy在评论中建议的)作为高效的类型测试,然后使用shell字符串比较而不是调用grep。

if [ "$(type -t somefunc)" = 'function' ]; then
    somefunc arg1 arg2
fi

而且更进一步,它还可以间接地起作用:

funcname=do_it_special_$somehow
if [ "$(type -t $funcname)" != 'function' ]; then
    funcname=do_it_normal
fi
$funcname arg1 arg2

我真的很喜欢这个解决方案,尽管感觉字符串中的反引号有些别扭。不过无论如何,我肯定会使用它。 - csexton
@csexton 你可以使用 "$(type -t somefunc)" 而不是反引号。 - wisbucky
不要使用这个。根据用户的语言,单词“function”可能不存在。 - Melroy van den Berg
@MelroyvandenBerg 需要引用出处。Bash文档列出了特定的字符串用于“-t”,没有提到本地化。 - Trevor Robinson
啊,你说得对。-t 参数应该始终被提供。这样可以解决问题,无论本地化如何。也就是说这是唯一正确的方式。或者查看退出代码。 - Melroy van den Berg

11
if type __git_ps1 | grep -q '^function$' 2>/dev/null; then
    PS1=whatever
fi

使用 typedeclare 更快 - 谢谢。 - csexton
6
这几乎是正确的,但如果__get_ps1是别名、内置命令等,它也会返回“true”。使用if type -t function_name | grep -q "^function$";then ... fi,确保__git_ps1是一个函数。 - Chen Levy
6
不需要使用 grep 命令;只需运行 type 命令,该命令将返回类型是否存在的真/假值。而且,无论您是否使用 type -t 命令都没有太大关系;如果已定义(标准的)__git_ps1,那么这可能是您想要用于 PS1 提示符的内容,无论它是如何定义的;即,if type __git_ps1 > /dev/null 2>&1 ; then PS1='\n\w $(__git_ps1)\n\!$ '; fi - michael
不要使用这个。根据用户的语言,单词“function”可能不存在。 - Melroy van den Berg

8

您可以使用以下方法进行操作:

type function_name

如果存在函数定义,in将返回一个函数定义。因此,您可以检查输出是否为空。

附注:更好的是,我刚刚检查它会输出函数不存在,否则输出函数主体。


我建议使用“-t”选项以避免本地化问题。 - Melroy van den Berg

6
如果您需要一个符合 /bin/sh 的版本,您不能使用 typesetdeclare 来测试函数定义,因为它不是shell内置命令。此外,type 命令的 -f 选项可能在某些系统上不可用。
我提出的解决方案部分涵盖在其他答案中:
isFunction() {
  type $1 | head -1 | egrep "^$1.*function\$" >/dev/null 2>&1;
  return;
}

isFunction __git_ps1 && PS1=__git_ps1

5

declare -F 'function_name' > /dev/null

echo $?

如果该函数存在,则$?的值为0,否则为1。


3

我认为最好使用declare,即使它比type稍微慢一些。Type也适用于别名或在PATH中的脚本。

我正在使用以下内容:

function function_exists
{
    FUNCTION_NAME=$1

    [ -z "$FUNCTION_NAME" ] && return 1

    declare -F "$FUNCTION_NAME" > /dev/null 2>&1

    return $?
}

所以在我的脚本中,我可以轻松地看到发生了什么:

if function_exists __git_ps1
then
    PS1=__git_ps1
fi

甚至可以使用仍然可读的一行代码:

function_exists __git_ps1 && PS1=__git_ps1

1

您可以列出所有可用的函数,或使用compgen检查单个函数:

help compgen

compgen -A function

compgen -A function myfunc 1>/dev/null && echo 'myfunc already exists' || exit 1

0
if declare -F | grep __git_ps1$
then
    PS1=whatever
fi

0
注意,busybox(极简的全能shell实现,在Windows上非常有用)有"type",但"type -t"打印错误的内容,因此我只检查type的返回值以查看某些东西是否可调用。busybox也没有declare。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接