在我的前同事处理用bash编写的项目时,我注意到所有.sh文件都只包含函数定义,而#!/bin/false
只是根据我的理解,这是一种防止执行的安全机制。仅包含文件。
示例:
my_foo.sh
#!/bin/false
function foo(){
echo foontastic
}
my_script.sh
#!/bin/bash
./my_foo.sh # does nothing
foo # error, no command named "foo"
. ./my_foo.sh
foo # prints "foontastic"
但是,当我不使用#!/bin/false
时,正确和不正确使用的效果完全相同:
示例:
my_bar.sh
function bar(){
echo barvelous
}
my_script.sh
#!/bin/bash
./my_bar.sh # spawn a subshell, defines bar and exit, effectively doing nothing
bar # error, no command named "bar"
. ./my_bar.sh
bar # prints "barvelous"
由于在两种情况下通过将source
包括在内来正确使用这些脚本可以按预期工作,并且在两种情况下执行它们都不会从父shell的角度执行任何操作并且不会生成有关无效使用的错误消息,这是什么这些脚本中#!/bash/false
的确切目的是什么?
答案 0 :(得分:4)
通常,让我们考虑一个带有bash代码的文件testcode
#!/bin/bash
if [ "$0" = "${BASH_SOURCE[0]}" ]; then
echo "You are executing ${BASH_SOURCE[0]}"
else
echo "You are sourcing ${BASH_SOURCE[0]}"
fi
你可以用它做三件事:
$ ./testcode
You are executing ./testcode
如果testcode具有正确的权限和正确的shebang,则此方法有效。使用#!/bin/false
的shebang,它不输出任何内容并返回1(false)的代码。
$ bash ./testcode
You are executing ./testcode
这完全忽略了shebang(甚至可能丢失),它只需要读取权限,而不是可执行权限。这是从Windows中的CMD命令行调用bash脚本的方法(如果你的PATH中有bash.exe
...),因为shebang机制不起作用。
$ . ./testcode
You are sourcing ./testcode
这也完全忽视了shebang,如上所述,但它完全不同,因为采购脚本意味着让当前的shell执行它,而 >执行脚本意味着调用新的shell来执行它。例如,如果在源脚本中放置exit
命令,则退出当前shell,这很少是您想要的。因此,源代码通常用于加载函数定义或常量,其方式有点类似于其他编程语言的import
语句,并且各种程序员开发不同的习惯来区分要执行的脚本和包含文件来源。我通常不对前者使用任何扩展名(其他人使用.sh
),但我对后者使用.shinc
的扩展名。你以前的同事使用了#!/bin/false
的shebang,只能问他们为什么他们更喜欢这种可能性。我想到的一个原因是你可以使用file
来区分这些文件:
$ file testcode testcode2
testcode: Bourne-Again shell script, ASCII text executable
testcode2: a /bin/false script, ASCII text executable
当然,如果这些包含文件只包含函数定义,那么执行它们是无害的,所以我不认为你的同事这样做是为了阻止执行。
我的另一个习惯,受Python世界的启发,是在我的.shinc
文件末尾进行一些回归测试(至少在开发时)
... function definitions here ...
[ "$0" != "${BASH_SOURCE[0]}" ] && return
... regression tests here ...
由于return
在执行的脚本中生成错误但在源脚本中是正常的,因此获得相同结果的更加神秘的方法是
... function definitions here ...
return 2>/dev/null || :
... regression tests here ...
答案 1 :(得分:1)
从父shell的角度来看,使用#!/bin/false
与否的区别在于返回码。
/bin/false
总是返回一个失败的返回码(在我的情况下为1,但不确定它是否是标准的)。
试试:
./my_foo.sh //does nothing
echo $? // shows "1", a.k.a failing
./my_bar.sh //does nothing
echo $? // shows "0", a.k.a. everything went right
因此,使用#!/bin/false
不仅记录了脚本不打算执行的事实,而且还会产生错误返回代码。