`#/bin/sh` 和 `#! /bin/sh` 之间有什么区别?
在Linux(以及其他一些POSIX系统)中,#!(称为shebang,没有空格)是execve(2)在可执行脚本的第一行,并紧跟可执行文件(称为解释器)时,execve(2)可以理解的。
如果您使用Linux,请阅读Advanced Linux Programming然后syscalls(2)。
空格(实际上缺少大部分空格)是重要的。
您可能会编写一个以#!/usr/bin/python开头的可执行Python脚本。使用chmod(1)使其可执行并查看inode(7)。您还可以拥有一些可执行的GNU guile脚本。
在某些Linux发行版上,/bin/sh是一个指向/bin/bash(即GNU bash)的符号链接。但是在其他发行版上,它是指向/bin/dash的(请参阅DASH网站)。这解释了它们之间的一些区别。
GNU bash有一个文档化的行为。所以阅读它的文档。
而且GNU bash是自由软件。因此,您可以研究它的源代码并进行改进。
此外,dash(像sash一样)是开源的。您可以研究其源代码并进行改进。
还阅读Advanced Linux Programming然后syscalls(2)和bash(1)。
请注意,/bin/sh在POSIX标准中有文档记录。
我最喜欢的Linux shell是zsh。您可以尝试fish(用C++编写,开源)或es,并使用chsh(1)设置您的登录shell(参见passwd(5)和shells(5))...
作为练习,您甚至可以编写自己的Unix shell。您可能想在其中使用GNU readline。还请参阅path_resolution(7)和glob(7)。
通过阅读您喜欢的shell的源代码,您肯定会学到很多东西。
一些shell接受插件(参见dlopen(3)和dlsym(3)...)。您可以为它们编写插件。
我建议您为此使用GNU emacs和git。但是保持您的shell脚本小。对于大型脚本(超过几百行),请使用比GNU bash更好的东西。
在某些情况下,会生成shell脚本。GNU autoconf就是这样一个生成器的例子。
在一个文件中,前两个字节组成一个16位整数,称为魔术数。操作系统可以根据魔术数确定如何处理这个文件。对于某些魔术数,后续的字节用于进一步区分更多细节。十六进制表示的魔术数2321定义了这是一个可以由某些语言处理器(如bash、perl、m4等)执行的文本文件,后续的字节表示实际要使用的语言处理器。如果在ASCII表中查找2321,它是#!
。
你的另外两个例子都不是有效的魔术数。
如果不想提供#!
行(尽管这通常是一个好主意),那么在执行脚本时,可以始终明确指定如何处理它。
例如,如果有一个名为foo
的文件,应该由bash运行,可以以以下方式开始(取决于bash在您的系统上的位置):
#!/usr/bin/bash
或者,如果要通过PATH找到bash,可以使用以下方式:
#!/usr/local/bin/env bash
然后设置脚本的可执行权限:
chmod u+x foo
然后通过键入以下命令来调用脚本:
./foo
或者不进行任何准备工作,通过以下命令调用脚本:
bash ./foo
更新:如triplee指出的那样,涉及env
的解决方案应该更好地编写为:
#!/usr/bin/env bash
即使在您的平台上存在/usr/local/bin,这样编写也更好,因为它可以更容易地将脚本移植到不同的主机上(希望在任何Linux或BSD环境中,包括MacOS,都存在/usr/bin/env)。
也许应该强调当#
后面没有紧跟!
时,它只是一个注释。
#!/usr/local/bin/env
很可能不存在;现在大多数地方,正确的shebang应该是#!/usr/bin/env
。
因此,我提到OP必须根据自己的环境调整路径。我只是因为懒惰而复制了自己环境的设置,其中env
位于/usr/local/bin
和/usr/bin
中。我同意特别是对于与其他平台兼容性的env
,/usr/bin
将是首选,我将相应地更新我的答案。