什么是等价于Python的`if __name__ =='__ main __'`?

时间:2015-04-30 11:24:46

标签: bash

在Bash中,我希望能够同时获取脚本并执行该文件。什么是Bash相当于Python的if __name__ == '__main__'

我没有在Stackoverflow上找到关于这个主题的现成问题/解决方案(我怀疑我问的方式与现有的问题/答案不符,但这是我能想到的最明显的方式因为我的Python经验来表达这个问题。)

P.S。关于possible duplicate question(如果我有更多时间,我会写一个较短的回复):

linked to question询问“如何检测脚本是否被源”但是这个问题询问“如何创建一个既可以源代码又可以作为脚本运行的bash脚本?”。这个问题的答案可能会使用前一个问题的某些方面,但还有其他要求/问题如下:

  • 一旦检测到脚本被采购,不运行脚本的最佳方法是什么(避免意外side-effects(除了导入感兴趣的功能),如添加/删除/修改环境/变量)
  • 一旦检测到正在运行脚本而不是源代码实现脚本的规范方法是什么(将它放在函数中?或者只是将它放在if语句之后?如果你把它放在if语句之后它会有副作用吗?
  • 我在Bash上发现的大多数谷歌搜索都没有涵盖这个主题(一个可以同时获取和执行的bash脚本)实现这个的规范方法是什么?这个话题没有被涵盖,因为它是沮丧还是不好?有没有问题?

5 个答案:

答案 0 :(得分:20)

解决方案:

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    main "$@"
fi

我添加了这个答案,因为我想要一个用模式编写的答案来模仿Python的if __name__ == '__main__',但是在Bash中。

关于BASH_SOURCE vs $_的使用情况。我使用BASH_SOURCE,因为它似乎比$_link1link2)更强大。

以下是我使用两个Bash脚本测试/验证的示例。

带有xyz()功能的

script1.sh:

#!/bin/bash

xyz() {
    echo "Entering script1's xyz()"
}

main() {
    xyz
    echo "Entering script1's main()"
}

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    main "$@"
fi
尝试调用函数xyz()

script2.sh:

#!/bin/bash

source script1.sh

xyz    

答案 1 :(得分:7)

没有。我通常用这个:

#!/bin/bash

main()
{
    # validate parameters

    echo "In main: $@"

    # your code here
}

main "$@"

如果您想知道此脚本是否为source,请将main电话打包到

if [[ "$_" != "$0" ]]; then
    echo "Script is being sourced, not calling main()" 
else
    echo "Script is a subshell, calling main()"
    main "$@"
fi

参考:How to detect if a script is being sourced

答案 2 :(得分:4)

使用FUNCNAME

方法1:测试FUNCNAME[0](Bash 4.3 +)

#!/bin/bash

main(){
    echo "hello"
}

if [[ ${FUNCNAME[0]} == "main" ]]; then
    main
fi

示例运行:

$ bash funcname_test.sh 
hello
$ source funcname_test.sh 
$ main
hello

我不确定我是如何偶然发现的。 man bash没有很好地描述其功能,但实际上它的实际作用是:

  • 已执行的脚本:${FUNCNAME[0]}main
  • 来源脚本:${FUNCNAME[0]}source
  • Shell函数:${FUNCNAME[0]}是函数的名称

方法2:在函数内部测试FUNCNAME[1](Bash 4.2)

在Bash 4.2中,FUNCNAME仅在函数中可用,其中FUNCNAME[0]是函数的名称,FUNCNAME[1]是调用者的名称。因此,对于顶级函数,FUNCNAME[1]将在已执行的脚本中为main,或在源脚本中为source

这个例子应该像上面的例子一样工作。

#!/bin/bash

get_funcname_1(){
    echo "${FUNCNAME[1]}"
}

main(){
    echo hello
}

if [[ $(get_funcname_1) == main ]]; then
    main
fi

答案 3 :(得分:2)

对于惯用的Bash方式,您可以像这样使用return

main(){
    echo hello
}

# End sourced section
return 2> /dev/null

main

示例运行:

$ bash return_test.sh 
hello
$ source return_test.sh 
$ main
hello

如果脚本来源,return将返回父(当然),但如果脚本执行,return将产生错误,脚本将继续执行。

我在GNU Bash 4.2,4.3和4.4

上测试了这个

这是基于mr.spuratic's answerHow to detect if a script is being sourced的部分内容。

请注意,此方法适用于Bash,但不适用于大多数其他shell。

答案 4 :(得分:1)

我一直在我所有脚本的底部使用以下构造:

[[ "$(caller)" != "0 "* ]] || main "$@"

脚本中的其他所有内容都在函数中定义,或者是全局变量。

caller被记录为“返回当前子例程调用的上下文”。当源脚本被来源时,调用者的结果从源于此脚本的脚本的行号开始。如果未提供此脚本,则以"0 "

开头

我使用!=||代替=&&的原因是后者会导致脚本在源文件时返回false。如果外部脚本在set -e下运行,则可能导致外部脚本退出。

请注意,我只知道这适用于bash。它不适用于posix shell。我不知道其他shell如ksh或zsh。