bash脚本中#!/ bin / false的用途

时间:2017-01-25 10:26:32

标签: bash shell

在我的前同事处理用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的确切目的是什么?

2 个答案:

答案 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不仅记录了脚本不打算执行的事实,而且还会产生错误返回代码。