什么是相当于Python的`if __name__ =='__ main __'的bash?

Tre*_*ith 29 bash

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

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


ps关于可能的重复问题(如果我有更多时间,我会写一个更短的回复):

链接到问题问:"如何检测如果脚本正在采购",但这个问题是问"你怎么创建一个bash脚本,既可以是采购和运行的脚本?".这个问题的答案可能会使用上一个问题的某些方面,但有其他要求/问题如下:

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

Tre*_*ith 25

解:

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    main "$@"
fi
Run Code Online (Sandbox Code Playgroud)

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

关于使用BASH_SOURCEVS $_.我使用BASH_SOURCE它是因为它看起来比$_(link1,link2)更健壮.


这是我用两个Bash脚本测试/验证的示例.

script1.sh xyz()功能:

#!/bin/bash

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

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

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    main "$@"
fi
Run Code Online (Sandbox Code Playgroud)

尝试调用函数的script2.sh xyz():

#!/bin/bash

source script1.sh

xyz    
Run Code Online (Sandbox Code Playgroud)


wja*_*rea 9

return 2> /dev/null

对于惯用的 Bash 方式来执行此操作,您可以return像这样使用:

_main(){
    echo hello
}

# End sourced section
return 2> /dev/null

_main
Run Code Online (Sandbox Code Playgroud)

运行示例:

$ bash return_test.sh 
hello
$ source return_test.sh 
$ _main
hello
Run Code Online (Sandbox Code Playgroud)

如果脚本是来源的,return将返回到父级(当然),但如果脚本被执行,return将产生一个隐藏的错误,并且脚本将继续执行。

我已经在 GNU Bash 4.2 到 5.0 上对此进行了测试,这是我的首选解决方案。

警告:这在大多数其他 shell 中不起作用。

这是基于Mr.spuraticHow to detector if a script is beingsourced的回答的一部分。


dek*_*ard 7

空无一人.我通常使用这个:

#!/bin/bash

main()
{
    # validate parameters

    echo "In main: $@"

    # your code here
}

main "$@"
Run Code Online (Sandbox Code Playgroud)

如果你想知道这个脚本是否source正好,请将你的main电话打包

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

参考:如何检测脚本是否来源


wja*_*rea 5

使用 FUNCNAME

方法1:测试FUNCNAME[0](Bash 4.3及更高版本)

#!/bin/bash

_main(){
    echo hello
}

if [[ ${FUNCNAME[0]} == "main" ]]; then
    _main
fi
Run Code Online (Sandbox Code Playgroud)

示例运行:

$ bash funcname_test.sh 
hello
$ source funcname_test.sh 
$ _main
hello
Run Code Online (Sandbox Code Playgroud)

我不确定我是怎么偶然发现的。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(){
    printf '%s\n' "${FUNCNAME[1]}"
}

_main(){
    echo hello
}

if [[ $(get_funcname_1) == main ]]; then
    _main
fi
Run Code Online (Sandbox Code Playgroud)