为啥需要将#!/bin/bash 放在脚本文件的开头?

Posted

技术标签:

【中文标题】为啥需要将#!/bin/bash 放在脚本文件的开头?【英文标题】:Why do you need to put #!/bin/bash at the beginning of a script file?为什么需要将#!/bin/bash 放在脚本文件的开头? 【发布时间】:2012-02-16 13:58:28 【问题描述】:

我之前制作了Bash 脚本,并且在没有#!/bin/bash 的开头它们都运行良好。

把它放进去有什么意义?会有什么不同吗?

另外,# 的发音如何?我知道! 发音为“bang”。

#! 怎么读?

【问题讨论】:

你不需要也不应该这样做,除非你别无选择。尽可能使用 '#!/bin/sh' 并了解 (POSIX) shell 和 bash 之间的区别。总有一天,你的简历会变得更长,你会发现自己在一个具有不同 shell 的系统上,但你仍然希望你的脚本能够工作。 读作“Hash-Bang”或“She-Bang”。 我认为值得注意的是,只有当您将脚本作为可执行文件运行时才会执行此操作。因此,如果您设置可执行标志,然后键入./yourscript.extension,例如./helloworld.py./helloworld.sh,它将在最上面一行查找解释器,即#!/bin/python!#/bin/bash,而在执行时像python helloworld.py 这样的脚本,第一行将不会被观察,因为它被注释掉了。所以它是 shell/kernel 的特殊序列。 @JFA 使用 !# 表示 python 和 #! 时, bash 和 python 之间的顺序是否发生变化?对于 bash ? @AjeyaAnand 不,这是一个错误的输入,很好理解 【参考方案1】:

这是一个约定,因此 *nix shell 知道要运行哪种解释器。

例如,旧版本的 ATT 默认使用 sh(Bourne shell),而旧版本的 BSD 默认使用 csh(C shell)。

即使在今天(大多数系统运行 bash,“Bourne Again Shell”),脚本也可以是 bash、python、perl、ruby、php 等。例如,您可能见#!/bin/perl#!/bin/perl5

PS: 感叹号 (!) 被亲切地称为“砰”。 shell 注释符号 (#) 有时称为 "hash"

PPS: 请记住 - 在 *nix 下,将后缀与文件类型相关联只是一个约定,而不是“规则”可执行文件可以是二进制程序,也可以是一百万种脚本类型中的任何一种,也可以是其他东西。因此需要#!/bin/bash

【讨论】:

我发现了其他有用的东西,$#。那叫什么? shebang 不是 shell 约定,它在处理execve(2) 系统调用时由内核 解释;所以 shebang 是一个 kernel 约定,而不是 shell 约定。 此外,如果文件没有扩展名,它还可以帮助 Vim 等编辑器确定语法高亮显示的语言。如果没有 shebang,Vim 将显示一个与纯文本文件相同的 bash 脚本。 我已经看到了很多没有真正解释的问题的答案——但你答案的最后一部分“可执行文件可以是二进制程序,一百万种脚本类型中的任何一种和其他的东西也是如此。因此需要#!/bin/bash." 真正做到了 所以... hash-bang-slash-bin-slash-bash?【参考方案2】:

更准确地说,shebang#!,当它是可执行文件xmode)文件的前两个字节时,由execve(2)系统解释调用(执行程序)。但是POSIX specification for execve不要提到shebang。

后面必须跟解释器可执行文件的文件路径(顺便说一句,它甚至可以是相对的,但大多数情况下是绝对的)。

在用户的$PATH 中找到解释器(例如python)的一个好技巧(或者可能是not so nice)是使用env 程序(在所有Linux 上总是在/usr/bin/env),例如

 #!/usr/bin/env python

任何 ELF 可执行文件都可以是解释器。如果您愿意,您甚至可以使用#!/bin/cat#!/bin/true! (但这通常是无用的)

【讨论】:

请参阅 this question,了解有关 #!/usr/bin/env hack 的讨论。 如果我想将参数传递给 python 我该怎么做实际上我想执行#!/usr/bin/env bash -x。我该怎么做? 它很简单,我自己发现了,只需在后面添加参数#!/usr/bin/env bash -x bash 几乎总是在 /bin/bash 所以你的 shebang 应该是 #!/bin/bash -x【参考方案3】:

它被称为shebang。在 unix-speak 中,# 被称为尖锐(如在音乐中)或哈希(如 twitter 上的标签),并且!称为砰。 (实际上,您可以使用 !! 引用您之前的 shell 命令,称为 bang-bang)。因此,当放在一起时,您会得到 haSH-BANG 或 shebang。

#! 之后的部分!告诉 Unix 使用什么程序来运行它。如果未指定,它将尝试使用 bash(或 sh、或 zsh,或任何您的 $SHELL 变量),但如果它在那里,它将使用该程序。另外,# 是大多数语言中的注释,因此该行在后续执行中会被忽略。

【讨论】:

如果我已经在 bash 中,如果它看到 #!/bin/bash 会启动另一个 bash 实例吗?如果我已经在 bash 中并且我把它排除在外怎么办?有什么区别吗? @javascriptninja 无论哪种方式,它都会启动一个新的 bash shell。就 bash 而言,只要您已经在使用 bash,就没有任何区别。 shebang 仅在以下情况下才真正重要:(a)您需要在不只是 shell 的东西中运行,例如 python 或 perl,或者(b)您不使用 bash shell(即您使用 zsh)但您需要运行需要在 bash 中运行的东西。 但是,在我看来,包含 shebang 是一种很好的做法,这样阅读代码的人就知道发生了什么。 错误:execve(2) 系统调用不要使用$SHELL 变量。解释 shebang 的是内核。 @BasileStarynkevitch 是正确的,内核中的精灵加载器解释了 shebang。我是说如果没有提供 shebang,将使用 $SHELL。【参考方案4】:

每个发行版都有一个默认的 shell。 Bash 是大多数系统的默认设置。如果您碰巧在具有不同默认 shell 的系统上工作,那么如果脚本是专门为 Bash 编写的,则它们可能无法按预期工作。

多年来,Bash 已经从 kshsh 获取代码。

添加#!/bin/bash 作为脚本的第一行,告诉操作系统调用指定的shell 来执行脚本中的命令。

#! 通常被称为“hash-bang”、“she-bang”或“sha-bang”。

【讨论】:

【参考方案5】:

操作系统采用默认 shell 来运行您的 shell 脚本。所以在脚本开头提到 shell 路径,你是在要求操作系统使用那个特定的 shell。对于portability 也很有用。

【讨论】:

【参考方案6】:

shebang 是一个指令,当您尝试执行相关文件时,加载程序使用在#! 之后指定的程序作为相关文件的解释器。因此,如果您尝试运行一个名为foo.sh 的文件,该文件的顶部有#!/bin/bash,那么实际运行的命令是/bin/bash foo.sh。这是为不同程序使用不同解释器的灵活方式。这是在系统级别实现的,用户级别的 API 是 shebang 约定。

还值得知道 shebang 是 magic number - 一种人类可读的,将文件标识为给定解释器的脚本。

即使没有shebang,您关于它“工作”的观点只是因为所讨论的程序是为与您正在使用的相同的shell编写的shell脚本。例如,您可以很好地编写一个 javascript 文件,然后放入一个 #! /usr/bin/js(或类似的东西)来生成一个 javascript“Shell 脚本”。

【讨论】:

【参考方案7】:

它被称为shebang。它由一个数字符号和一个感叹号字符 (#!) 组成,后跟解释器的完整路径,例如 /bin/bash。 UNIX 和 Linux 下的所有脚本都使用第一行指定的解释器执行。

【讨论】:

【参考方案8】:

“Bourne-Again shell”的 Bash 标准只是众多可用标准中的一种 Linux 中的 shell。

shell 是一个命令行解释器,它接受并运行命令。

Bash 通常是大多数 Linux 发行版中的默认 shell。这就是为什么 bash 是 与外壳同义。

shell 脚本通常具有几乎相同的语法,但有时它们也不同。例如,数组索引在 Zsh 中从 1 开始,而不是在 bash 中从 0 开始。一个脚本 如果它有数组,那么为 Zsh shell 编写的 bash 在 bash 中将无法正常工作。

为避免令人不快的意外,您应该告诉解释器您的 shell 脚本 是为 bash shell 编写的。你是怎么做到的?

只需在 #!/bin/bash 中开始您的 bash 脚本

【讨论】:

【参考方案9】:

您还会在#!/bin/bash 之后看到一些其他参数, 例如#!/bin/bash -v -x 阅读本文以获得更多想法。https://unix.stackexchange.com/questions/124272/what-do-the-arguments-v-and-x-mean-to-bash 。

【讨论】:

【参考方案10】:

对于使用不同系统但没有现成可用库的人可能很有用。如果没有声明,并且您的脚本中有一些该系统不支持的函数,您应该声明#/bin/bash。我以前在工作中遇到过这个问题,现在我只是把它作为一种练习。

【讨论】:

以上是关于为啥需要将#!/bin/bash 放在脚本文件的开头?的主要内容,如果未能解决你的问题,请参考以下文章

bash 脚本

bash 脚本编程一 文件头,注释 和 变量

Bash scripts

inotify为啥无法检视共享文件夹

Linux bash输出带日期时间的日志文件

Linux bash输出带日期时间的日志文件