检查一个函数是否被定义

4

我有一个简单的脚本来检查rbenv是否是一个函数,当我在shell中输入: $ type rbenv | grep "rbenv is a function" 时,我得到了积极的结果,shell响应是rbenv是一个函数 然后我想在一个脚本中执行这个操作,所以我在我的文件中写入:

#!/bin/bash
if  type rbenv | grep -q "rbenv is a function" ;
then
  echo "success!"
else
  echo "something went wrong."
fi

我无法让这个功能正常运行,脚本的结果是something went wrong.我想要让它正常工作,并且了解是否有更好的解决方案来完成此任务。

我也尝试了这个版本的脚本但没有成功。

if  [[ $(type rbenv | head -1) == "rbenv is a function" ]] ;
...

在shell中输入type rbenv | head -1,输出的结果应该是rbenv is a function。我不知道我做错了什么,请指出我的错误。

解决这个问题的部分方法是在运行脚本之前在你的shell中运行export -f rbenv,但这不是正确的方法,对吧?

完整的解决方案是,需要重新按照安装rbenv的步骤进行操作,并将其放在if语句之前:

export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"

我要感谢参与讨论的所有人,他们引导我找到了解决方案 :)


3
你是否已经导出该函数 - tripleee
你如何定义 rbenv?你需要导出它以使子 shell 可见。 - perreal
rbenv是一组脚本,用于从此处https://github.com/sstephenson/rbenv运行多个版本的ruby,并且如果您指的是导出,它在我的PATH中,但是在我的脚本中仅运行`type rbenv会给出其他结果rbenv is /home/simone/.rbenv/bin/rbenv,并且从我的外部脚本输出导出./rbenv_check: line 2: export: rbenv: not a function`。 - Szymon Błaszczyński
如果它是一个函数,它不能在你的PATH中。导出一个函数意味着说export -f rbenv。请参见下面的答案。 - tripleee
1
我在想,也许你想要_source_相关脚本而不是将其作为子进程执行——在这种情况下,它将在与其父进程相同的 shell 中运行,因此根本不需要导出任何内容。 - Charles Duffy
显示剩余3条评论
4个回答

6
我的直觉是你没有导出你的函数。尝试:
export -f rbenv

在运行脚本之前,应将此函数设置为可见,以便子shell可以看到它,例如在运行shell脚本时启动的子shell。
根据您要完成的任务,更好的解决方案可能是将代码定义为 .bashrc 或类似文件中的函数,而不是作为单独的脚本。
此外,您的代码可以变得更加健壮。消息的输出格式可能会在下一次Bash升级中更改,或者您可能会在某一天使用本地化为其他语言的Bash。
case $(type -t rbenv) in
    function) echo Success;;
    *) echo Something went wrong;;
esac

(从if test切换到case仅是个人习惯和鼓吹,不是关键修改。)

好的,现在我明白了,我需要将整个rbenv脚本导出为一个函数到我的子shell中...但是如果我想要在外部脚本中完成这个导出测试,该怎么办呢?我想编写一个用于rbenv安装的脚本,但如果我无法从我的脚本中导出rbenv(请参考我的编辑评论),我该如何检查它是否为一个函数? - Szymon Błaszczyński
我一直在寻找这个。谢谢! - pegasuspect

3

完整解决方案

显然,我需要重复安装rbenv的步骤,因为它需要放在if语句之前的行中。这些行可以在Ubuntu桌面上的~/.bashrc、Zsh shell中的~/.zshrc或其他任何Linux版本中的~/.bash_profile中找到。

export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"

只有这样,它才能完整加载 rbenv 脚本到我的 rbenv 安装脚本中,并且我才能使用以下代码检查其是否为函数:
if  type rbenv | grep -q "rbenv is a function" ;
then
  echo "success!"
else
  echo "something went wrong."
fi
[ "$( type -t rbenv )" == "function" ]是tripleee建议的更好的方法,可以在if语句中使用。虽然我不是shell黑客,但它似乎更加符合编码规范和可重用性。 我要感谢所有参与讨论并指导我解决问题的人 :)

2
你也可以使用例如 [ "$( type -t rbenv )" == "function" ]。这是一个更简洁的方法,正如@tripleee所建议的那样。 - zerodiff

2

判断函数是否被定义的两种方法

方法1:

if [ `type -t rbenv` = "function" ];
then echo "'rbenv' is     a function"
else echo "'rbenv' is not a function"
fi

方法2:
if `declare -F rbenv`; then echo "'rbenv' is     a function"
                       else echo "'rbenv' is not a function"
fi

0
好的,但在我的情况下,我想从我的脚本中导出此函数,该脚本与rbenv脚本分开,是的,从我的脚本导出的输出会给出./rbenv_check: line 2: export: rbenv: not a function,因此我无法在我的脚本内部执行此操作,但我想在这里完成此操作。我的想法是,在安装rbenv时,也许函数将留在脚本中,只有这样我才能从脚本内部检查它,但我已经从这个检查开始编写,以确保一切正确。
这不是您最初问题的答案,而是关于尝试从shell脚本内部导出函数的内容。
Export告诉您的shell将该项复制到后续命令中。由于您的shell脚本已经是子shell,因此您的函数不存在。它已经消失了。没有了。你有两个选择:
  • 简单的方法:在运行shell脚本之前导出函数。
  • 困难的方法:这需要一些设置:
我认为您的函数是在登录时执行的某个文件中定义的。将您想要的所有这些函数放入另一个文件中。假设是$HOME/.functions
现在,无论何处您需要在后续的 shell 脚本中使用这些函数,都可以在脚本中引用该文件:
if [[ -x $HOME/.functions ]]
then
    source $HOME/.functions
else
    echo "ERROR: The $HOME/.functions function definitions are missing." >&2
    echo "ERROR: This script is exiting." >&2
    exit 2
fi

你可以将以下行放入你的$HOME/.bash_profile文件中,这样你就可以在默认的shell中使用这些函数。
[[ -x $HOME/.functions ]] && source $HOME/.functions

请注意,如果找到函数,则我只会将其源代码引入,而不会打印错误消息并退出。您不希望在自己的.bash_profile脚本中这样做。否则,一旦出现错误,您就无法登录。

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