在我的前同事处理用bash编写的项目时,我注意到所有.sh文件都只包含函数定义#!/bin/false,据我所知,这是一种防止执行仅包含文件的安全机制.
例:
my_foo.sh
#!/bin/false
function foo(){
echo foontastic
}
Run Code Online (Sandbox Code Playgroud)
my_script.sh
#!/bin/bash
./my_foo.sh # does nothing
foo # error, no command named "foo"
. ./my_foo.sh
foo # prints "foontastic"
Run Code Online (Sandbox Code Playgroud)
但是,当我不使用时#!/bin/false,正确和不正确使用的效果完全相同:
例:
my_bar.sh
function bar(){
echo barvelous
}
Run Code Online (Sandbox Code Playgroud)
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"
Run Code Online (Sandbox Code Playgroud)
由于source在两种情况下正确使用这些脚本都可以按预期工作,并且在两种情况下执行它们都不会从父shell的角度执行任何操作并且不会生成有关无效使用的错误消息#!/bash/false,这些脚本的目的究竟是什么?
一般来说,让\xe2\x80\x99s考虑一个testcode包含bash代码的文件
#!/bin/bash\nif [ "$0" = "${BASH_SOURCE[0]}" ]; then\n echo "You are executing ${BASH_SOURCE[0]}"\nelse \n echo "You are sourcing ${BASH_SOURCE[0]}"\nfi\nRun Code Online (Sandbox Code Playgroud)\n\n你可以用它做三件不同的事情:
\n\n$ ./testcode\nYou are executing ./testcode\nRun Code Online (Sandbox Code Playgroud)\n\n如果测试代码具有正确的权限和正确的 shebang,则此方法有效。如果 shebang 为#!/bin/false,则不会输出任何内容并返回代码 1(假)。
$ bash ./testcode\nYou are executing ./testcode\nRun Code Online (Sandbox Code Playgroud)\n\n这完全忽略了 shebang(甚至可能会丢失),它只需要读取权限,不需要可执行权限。这是在 Windows 中从 CMD 命令行调用 bash 脚本的方法(如果您bash.exe的 PATH 中有...),因为 shebang 机制不起作用\xe2\x80\x99。
$ . ./testcode\nYou are sourcing ./testcode\nRun Code Online (Sandbox Code Playgroud)\n\n如上所述,这也完全忽略了 shebang,但这是完全不同的事情,因为获取脚本意味着让当前 shell 执行它,而执行脚本意味着调用一个新的 shell 来执行它。例如,如果您将exit命令放入源脚本中,则会从当前 shell 退出,这很少是您想要的。因此,采购通常用于加载函数定义或常量,其方式有点类似于import其他编程语言的语句,并且不同的程序员养成了不同的习惯来区分要执行的脚本和要采购的文件。我通常不\xe2\x80\x99t 对前者使用任何扩展名(其他人使用),但我对后者.sh使用扩展名。.shinc你的前同事使用了一个shebang #!/bin/false,人们只能问他们为什么他们更喜欢这个而不是其他无数的可能性。我想到的原因之一是您可以用来file区分这些文件:
$ file testcode testcode2\ntestcode: Bourne-Again shell script, ASCII text executable\ntestcode2: a /bin/false script, ASCII text executable\nRun Code Online (Sandbox Code Playgroud)\n\n当然,如果这些包含文件只包含函数定义,那么执行它们是无害的,所以我不认为你的同事这样做是为了阻止执行。
\n\n受 Python 世界启发,我的另一个习惯是在文件末尾放置一些回归测试.shinc(至少在开发过程中)
... function definitions here ...\n\n[ "$0" != "${BASH_SOURCE[0]}" ] && return \n\n... regression tests here ...\nRun Code Online (Sandbox Code Playgroud)\n\n由于return在执行的脚本中生成错误,但在源脚本中生成错误,因此获得相同结果的更神秘的方法是
... function definitions here ...\n\nreturn 2>/dev/null || :\n\n... regression tests here ...\nRun Code Online (Sandbox Code Playgroud)\n