我应该在 Bash 脚本中使用 Shebang 吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25165808/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 11:03:36  来源:igfitidea点击:

Should I use a Shebang with Bash scripts?

bashshellshshebang

提问by Steven Penny

I am using Bash

我正在使用 Bash

$ echo $SHELL
/bin/bash

and starting about a year ago I stopped using Shebangs with my Bash scripts. Can I benefit from using #!/bin/shor #!/bin/bash?

从大约一年前开始,我停止在 Bash 脚本中使用 Shebangs。我可以从使用#!/bin/sh或 中受益#!/bin/bash吗?

Update: In certain situations a file is only treated as a script with the Shebang, example

更新:在某些情况下,文件仅被视为带有 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

回答by Roland Smith

On UNIX-like systems, you should alwaysstart scripts with a shebang line. The system call execve(which is responsible for starting programs) relieson an executable having either an executable header or a shebang line.

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

From FreeBSD's execve manual page:

从 FreeBSD 的execve 手册页

 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
 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

Similarly from the Linux manual page:

同样来自Linux 手册页

execve() executes the program pointed to by filename. filename must be either a binary executable, or a script starting with a line of the form:

#! interpreter [optional-arg]

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

#! interpreter [optional-arg]

In fact, if a file doesn't have the right "magic number" in it's header, (like an ELF header or #!), execvewill failwith the ENOEXEC error (again from FreeBSD's execve manpage):

事实上,如果一个文件的头文件中没有正确的“幻数”(如 ELF 头文件或#!),execve将会失败并显示 ENOEXEC 错误(同样来自 FreeBSD 的 execve 手册页):

[ENOEXEC] The new process file has the appropriate access permission, but has an invalid magic number in its header.

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



If the file has executable permissions, but no shebang line but does seem to be a text file, the behaviour depends on the shell that you're running in.

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

Most shells seem to start a new instance of themselves and feed it the file, see below.

大多数 shell 似乎启动了一个自己的新实例并将文件提供给它,见下文。

Since there is no guarantee that the script was actually written for that shell, this can work or fail spectacularly.

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

From tcsh(1):

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.
   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.

From FreeBSD's sh(1):

来自 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.

From bash(1):

来自 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.
   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.


You cannot always depend on the location of a non-standard program like bash. I've seen bash in /usr/bin, /usr/local/bin, /opt/fsf/binand /opt/gnu/binto name a few.

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

So it is generally a good idea to use env;

所以通常使用env;

#!/usr/bin/env bash

If you want your script to be portable, use shinstead of bash.

如果你希望你的脚本是便携式的,可以使用sh替代bash

#!/bin/sh

While standards like POSIX do not guaranteethe absolute paths of standard utilities, most UNIX-like systems seem to have shin /binand envin /usr/bin.

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

回答by Barmar

Scripts should always begin with a shebang line. If a script doesn't start with this, then it may be executed by the current shell. But that means that if someone who uses your script is running a different shell than you do, the script may behave differently. Also, it means the script can't be run directly from a program (e.g. the C exec()system call, or find -exec), it has to be run from a shell.

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

回答by jlliagre

  • If you write bashscripts, i.e. non portable scripts containing bashisms, you should keep using the #!/bin/bashshebang just to be sure the correct interpreter is used. You should not replace the shebang by #!/bin/shas bash will run in POSIX mode so some of your scripts might behave differently.

  • If you write portablescripts, i.e. scripts only using POSIX utilities and their supported options, you might keep using #!/bin/shon yoursystem (i.e. one where /bin/shis a POSIX shell).

  • It you write stricly conforming POSIX scriptsto be distributed in various platforms and you are sure they will only be launched from a POSIX conforming system, you might and probably should remove the shebang as stated in the POSIX standard:

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

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

  • 如果您编写了严格符合 POSIX 脚本以分发到各种平台,并且您确定它们只会从符合 POSIX 的系统中启动,您可能并且可能应该删除 POSIX 标准中所述的shebang:

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

就目前而言,严格遵守的应用程序不得使用“#!” 作为文件的前两个字符。

The rationale is the POSIX standard doesn't mandate /bin/shto be the POSIX compliant shell so there is no portable way to specify its path in a shebang. In this third case, to be able to use the 'find -exec' syntax on systems unable to run a shebangless still executable script, you can simply specify the interpreter in the find command itself, eg:

基本原理是 POSIX 标准不/bin/sh强制要求成为符合 POSIX 的 shell,因此没有可移植的方式在 shebang 中指定其路径。在这第三种情况下,为了能够在无法运行 shebangless 仍然可执行脚本的系统上使用“find -exec”语法,您可以简单地在 find 命令本身中指定解释器,例如:

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

Here, as shis specified without a path, the POSIX shell will be run.

在这里,正如sh没有指定路径一样,将运行 POSIX shell。

回答by jrjc

You might be interested in an early descriptionby Dennis M Ritchie (dmr) who invented the #!:

您可能对发明了以下内容的Dennis M Ritchie ( )的早期描述感兴趣:dmr#!

From uucp Thu Jan 10 01:37:58 1980

.>From dmr Thu Jan 10 04:25:49 1980 remote from research

The system has been changed so that if a file being executed begins with the magic characters #! , the rest of the line is understood to be the name of an interpreter for the executed file. Previously (and in fact still) the shell did much of this job; it automatically executed itself on a text file with executable mode when the text file's name was typed as a command. Putting the facility into the system gives the following benefits.

1) It makes shell scripts more like real executable files, because they can be the subject of 'exec.'

2) If you do a 'ps' while such a command is running, its real name appears instead of 'sh'. Likewise, accounting is done on the basis of the real name.

3) Shell scripts can be set-user-ID.

4) It is simpler to have alternate shells available; e.g. if you like the Berkeley csh there is no question about which shell is to interpret a file.

5) It will allow other interpreters to fit in more smoothly.

To take advantage of this wonderful opportunity, put

   #! /bin/sh

at the left margin of the first line of your shell scripts. Blanks after ! are OK. Use a complete pathname (no search is done). At the moment the whole line is restricted to 16 characters but this limit will be raised.

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

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

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

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

2) 如果在运行这样的命令时执行 'ps',则会显示其真实名称而不是 'sh'。同样,记账也是实名制。

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

4) 有可用的备用外壳更简单;例如,如果您喜欢 Berkeley csh,那么关于哪个 shell 来解释文件是没有问题的。

5) 可以让其他口译员更顺利地融入。

为了利用这个绝好的机会,把

   #! /bin/sh

在 shell 脚本第一行的左边距。后空白!没问题。使用完整的路径名(不进行搜索)。目前整行被限制为 16 个字符,但这个限制将会提高。

Hope this helps

希望这可以帮助

回答by pyrrhic

The header is useful since it specifies which shell to use when running the script. For example, #!/bin/zshwould change the shell to zsh instead of bash, where you can use different commands.

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

For example, this pagespecifies the following:

例如,此页面指定以下内容:

Using #!/bin/sh, the default Bourne shell in most commercial variants of UNIX, makes the script portable to non-Linux machines, though you sacrifice Bash-specific features ...

使用 #!/bin/sh(大多数 UNIX 商业变体中的默认 Bourne shell)使脚本可移植到非 Linux 机器,尽管您牺牲了 Bash 特定的功能......

回答by Chirality

$SHELL and #!/bin/bash or #!/bin/sh are different.

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

To start, #!/bin/sh is a symlink to /bin/bash on most Linux systems (on Ubuntu it is now /bin/dash)

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

But on whether to start with /bin/sh or /bin/bash:

但是关于是从 /bin/sh 还是 /bin/bash 开始:

Bash and sh are two different shells. Basically bash is sh, with more features and better syntax. Most commands work the same, but they are different.

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

Just assume if you're writing a bash script, stick with /bin/bash and not /sh because problems can arise.

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

$SHELL does not necessarily reflect the currently running shell. Instead, $SHELL is the user's preferred shell, which is typically the one set in /etc/passwd. If you start a different shell after logging in, you can not necessarily expect $SHELL to match the current shell anymore.

$SHELL 不一定反映当前运行的 shell。相反,$SHELL 是用户的首选 shell,通常是 /etc/passwd 中的设置。如果您在登录后启动不同的 shell,您就不一定期望 $SHELL 与当前的 shell 匹配。

This is mine for example, but it could also be /root:/bin/dash or /root:/bin/sh depending on which shell you have input in passwd. So to avoid any problems, keep the passwd file at /bin/bash and then using $SHELL vs. #!/bin/bash wouldn't matter as much.

例如,这是我的,但它也可以是 /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

Sources: http://shebang.mintern.net/bourne-is-not-bash-or-read-echo-and-backslash/https://unix.stackexchange.com/questions/43499/difference-between-echo-shell-and-which-bashhttp://man.cx/shhttp://man.cx/bash

资料来源:http: //shebang.mintern.net/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

回答by Konrad H?ffner

In addition to what the others said, the shebang also enables syntax highlighting in some text editors, for example vim.

除了其他人所说的之外,shebang 还可以在某些文本编辑器中启用语法突出显示,例如 vim。