这与 确定 bash 中是否存在函数基本是同一个问题,只不过这次不是针对 Bash,而是针对 a POSIX shell:
如何判断给定名称的shell函数是否存在?
似乎像
type
这样的典型内置函数都不是 POSIX 强制要求的,所以这个问题更加困难,甚至可能是不可能的。
为了完整起见:可以使用
type
或 command -V
而不产生任何额外的子进程,如 sed
或 grep
(尽管您仍然需要为 $(type ...)
产生一个子进程):
is_function() {
case "$(type -- "$1" 2>/dev/null)" in
*function*) return 0 ;;
esac
return 1
}
POSIX(更准确地说是X/开放可移植性指南)指定type命令。它没有说明
type
命令应该返回什么来告诉参数是什么。然而,标准表示它通常标识操作数,因此 type
实现在传递函数名称时不太可能不在其回复中包含字符串“function”。
这应该适用于大多数(如果不是全部)符合 POSIX 的 shell:
isFunction()
{
type "$1" | sed "s/$1//" | grep -qwi function
}
您也可以在此处运行
command -V
而不是 type
,对未指定的输出格式具有相同的注释。我从来不这样做,因为前者打字更短,更容易记住。但是,如果您运行的 shell 决定不包含 XSI(可能是 posh
),即通过将其尝试遵守的实用程序限制为严格的 POSIX 集,从而破坏了许多现有脚本的可移植性,那么这将是强制性的.
您可以在实现 2013 版 POSIX 的 shell 中使用
command
或旧规范的用户可移植性实用程序选项:
isFunction() {
command -V "$1" 2>/dev/null | grep -qwi function
}
但是,请注意,规范实际上并未规定命令输出的形式。 它要求函数被如此识别,因此当且仅当请求的名称是函数时,输出很可能包含单词
function
,但不严格保证。上述解决方案很容易被愚弄(请参阅@jiliagre的评论)。
type
命令执行几乎相同的操作(对于未指定的输出格式具有相同的警告)。奇怪的是,它没有被列为 shell 内置命令之一,但正如信息注释所说,它几乎必须是一个才能按指定工作。
在这些情况下,此处的其他答案将返回
foo
的误报:
/tmp/function/foo
是可执行的,并且 $PATH
包括 /tmp/function
alias foo='echo function'
已运行更稳健的方法如下:
is_function() {
[ -n "$1" ] && [ "$(command -v -- "$1")" = "$1" ] || return 1
[ "$(command -V -- "$1")" != "$(unset -f -- "$1"; command -V -- "$1" 2>/dev/null)" ]
}
第一行确保
$1
存在,并且不是 $PATH
中的别名或可执行文件。然后我们检查 command -V
的输出,尝试在子 shell 中取消设置名为 $1
的函数,然后再次检查 command -V
。如果输出不同,$1
一定是一个函数。