我应该使用带Bash脚本的Shebang吗?

时间:2014-08-06 16:48:04

标签: bash shell sh shebang

我正在使用Bash

$ echo $SHELL
/bin/bash

从大约一年前开始,我停止使用Shebangs和我的Bash脚本。能够 我可以使用#!/bin/sh#!/bin/bash

更新:在某些情况下,文件仅被视为带有的脚本 Shebang,例子

$ cat foo.sh
ls

$ cat bar.sh
#!/bin/sh
ls

$ file foo.sh bar.sh
foo.sh: ASCII text
bar.sh: POSIX shell script, ASCII text executable

7 个答案:

答案 0 :(得分:39)

在类UNIX系统上,您应该始终使用shebang行启动脚本。系统调用execve(负责启动程序)依赖于具有可执行标头或shebang线的可执行文件

来自FreeBSD的execve manual page

 The execve() system call transforms the calling process into a new
 process.  The new process is constructed from an ordinary file, whose
 name is pointed to by path, called the new process file.
 [...]

 This file is
 either an executable object file, or a file of data for an interpreter.

 [...]

 An interpreter file begins with a line of the form:

       #! interpreter [arg]

 When an interpreter file is execve'd, the system actually execve's the
 specified interpreter.  If the optional arg is specified, it becomes the
 first argument to the interpreter, and the name of the originally
 execve'd file becomes the second argument

同样来自Linux manual page

  

execve()执行filename指向的程序。文件名必须是   二进制可执行文件,或以一行开头的脚本   形式:

#! interpreter [optional-arg]

事实上,如果某个文件的标题中没有正确的“幻数”(如ELF标题或#!),则execve失败 ENOEXEC错误(再次来自FreeBSD的execve手册页):

  

[ENOEXEC]新进程文件具有适当的访问权限              权限,但其中包含无效的幻数              报头中。


如果文件具有可执行权限,但没有shebang行但似乎确实是文本文件,则行为取决于您正在运行的shell。

大多数shell似乎开始自己的新实例并将其提供给文件,见下文。

由于无法保证脚本实际上是为该shell编写的,因此这可能会起作用或失败。

来自tcsh(1)

   On  systems which do not understand the `#!' script interpreter conven‐
   tion the shell may be compiled to emulate it;  see  the  version  shell
   variable.  If so, the shell checks the first line of the file to see if
   it is of the form `#!interpreter arg ...'.  If it is, the shell  starts
   interpreter  with  the  given args and feeds the file to it on standard
   input.

来自FreeBSD的sh(1)

If the program is not a normal executable file (i.e., if it
     does not begin with the “magic number” whose ASCII representation is
     “#!”, resulting in an ENOEXEC return value from execve(2)) but appears to
     be a text file, the shell will run a new instance of sh to interpret it.

来自bash(1):

   If this execution fails because the file is not in  executable  format,
   and  the file is not a directory, it is assumed to be a shell script, a
   file containing shell commands.  A subshell is spawned to  execute  it.

您不能总是依赖于非标准程序(如bash)的位置。我在/usr/bin/usr/local/bin/opt/fsf/bin/opt/gnu/bin中看过bash,仅举几例。

因此,使用env;

通常是个好主意
#!/usr/bin/env bash

如果您希望自己的脚本可移植,请使用sh代替bash

#!/bin/sh

虽然像POSIX这样的标准不保证标准实用程序的绝对路径,但大多数类似UNIX的系统似乎在sh/bin中都有env /usr/bin

答案 1 :(得分:13)

脚本应始终以shebang行开头。如果脚本没有以此开头,那么它可能由当前shell执行。但这意味着,如果使用您的脚本的人运行的是与您不同的shell,则脚本的行为可能会有所不同。此外,这意味着脚本不能直接从程序运行(例如C exec()系统调用,或find -exec),它必须从shell运行。

答案 2 :(得分:3)

  • 如果你编写 bash 脚本,即包含bashisms的非可移植脚本,你应该继续使用#!/bin/bash shebang,以确保使用正确的解释器。您不应该用#!/bin/sh替换shebang,因为bash将在POSIX模式下运行,因此您的某些脚本可能会有不同的行为。

  • 如果您编写可移植脚本,即仅使用POSIX实用程序及其支持选项的脚本,您可能会继续在 系统上使用#!/bin/sh(即/bin/sh是POSIX shell的那个。)

  • 您编写严格符合POSIX脚本以在各种平台上分发,并且您确信它们只能从符合POSIX的系统启动,您可能并且可能应该删除shebang在POSIX标准中说明:

As it stands, a strictly conforming application must not use "#!" as the first two characters of the file.

理由是POSIX标准不要求/bin/sh成为POSIX兼容的shell,因此没有可移植的方法来指定它在shebang中的路径。在第三种情况下,为了能够在无法运行shebangless仍然可执行脚本的系统上使用'find -exec'语法,您只需在find命令本身中指定解释器,例如:

find /tmp -name "*.foo" -exec sh -c 'myscript "$@"' sh {} + 

这里,由于指定了sh而没有路径,因此将运行POSIX shell。

答案 3 :(得分:3)

您可能对发明dmr的Dennis M Ritchie(#!)的early description感兴趣:

  

来自uucp Thu Jan 10 01:37:58 1980

     

。>来自dmr Thu Jan 10 04:25:49 1980远离研究

     

系统已更改,如果是文件   正在执行的是魔术角色#! , 剩下的   line被理解为执行的解释器的名称   文件。以前(实际上仍然),shell完成了大部分工作;   它在具有可执行模式的文本文件上自动执行   当文本文件的名称被输入为命令时。放置设施   进入系统会带来以下好处。

     

1)它使shell脚本更像真正的可执行文件,因为   他们可以成为'执行'的主题。

     

2)如果在运行这样的命令时执行'ps',则使用其真实姓名   出现而不是'sh'。同样,会计是在此基础上完成的   真实姓名。

     

3)Shell脚本可以设置为user-ID。

     

4)提供替代炮弹比较简单;例如如果你喜欢   Berkeley csh毫无疑问是关于哪个shell   解释一个文件。

     

5)它将允许其他口译员更顺利地适应。

     

利用这个绝佳的机会,把

   #! /bin/sh
     

在shell脚本第一行的左边缘。空白   之后!没关系使用完整的路径名(不进行搜索)。在   整个行限制为16个字符,但这个限制   将被提出。

希望这有帮助

答案 4 :(得分:1)

标头很有用,因为它指定运行脚本时要使用的shell。例如,#!/bin/zsh会将shell更改为zsh而不是bash,您可以在其中使用不同的命令。

例如,this page指定以下内容:

  

使用#!/ bin / sh,大多数商业版本中的默认Bourne shell   UNIX,使脚本可以移植到非Linux机器上,尽管你   牺牲Bash特有的功能......

答案 5 :(得分:0)

$ SHELL和#!/ bin / bash或#!/ bin / sh是不同的。

首先,#!/ bin / sh是大多数Linux系统上/ bin / bash的符号链接(在Ubuntu上它现在是/ bin / dash)

但是关于是否以/ bin / sh或/ bin / bash开头:

  

Bash和sh是两种不同的贝壳。基本上bash是sh,更多   功能和更好的语法。大多数命令的工作方式相同,但它们都是   不同。

假设您正在编写bash脚本,请坚持使用/ bin / bash而不是/ sh,因为可能会出现问题。

  

$ SHELL不一定反映当前正在运行的shell。   相反,$ SHELL是用户首选的shell,通常是   一个在/ etc / passwd中设置。如果在记录后启动另一个shell   在,你不一定要期望$ SHELL匹配当前的shell   了。

这是我的例子,但它也可以是/ root:/ bin / dash或/ root:/ bin / sh,具体取决于你在passwd中输入的shell。所以为了避免任何问题,将passwd文件保存在/ bin / bash然后使用$ SHELL与#!/ bin / bash无关紧要。

root@kali:~/Desktop# cat /etc/passwd
root:x:0:0:root:/root:/bin/bash

来源: http://shebang.brandonmintern.com/bourne-is-not-bash-or-read-echo-and-backslash/ https://unix.stackexchange.com/questions/43499/difference-between-echo-shell-and-which-bash http://man.cx/sh http://man.cx/bash

答案 6 :(得分:0)

除了其他人所说的,shebang还可以在一些文本编辑器中启用语法高亮,例如vim。