这可能是一个愚蠢的问题,但我仍然要问。如果我在my_shell_script.sh的开头声明了shebang

#!/bin/bash 


,那么我总是必须始终使用bash调用此脚本

[my@comp]$bash my_shell_script.sh


还是可以使用eg

[my@comp]$sh my_shell_script.sh


,我的脚本使用shebang确定正在运行的shell? ksh shell会发生同样的情况吗?我正在使用AIX。

评论

您会有一些困惑:执行“ _some_shell some_script”时,它会启动_some_shell并要求其解释some_script。所以不,如果您执行“ sh my_shell_script.sh”,它将不会解释shebang,而是会在sh中解释脚本。要使用shebang:chmod + x my_shell_script.sh; /path/to/my_shell_script.sh#或./my_shell_script.sh(如果您恰巧位于其目录中)

#1 楼

shebang #!是由字节字符串0x23 0x21组成的魔术数字的人类可读实例,exec()函数系列使用该字符串来确定要执行的文件是脚本还是二进制文件。存在shebang时,exec()将改为运行shebang之后指定的可执行文件。

请注意,这意味着如果您通过在命令行上指定解释器来调用脚本,则两种情况都一样问题中给出的exec()将执行在命令行上指定的解释器,甚至不会查看脚本。

因此,正如其他人指出的那样,如果您希望exec()调用指定的解释器,在shebang行上,脚本必须设置可执行位并作为./my_shell_script.sh调用。

使用以下脚本可以轻松演示该行为:

#!/bin/ksh
readlink /proc/$$/exe


说明:


#!/bin/kshksh定义为解释器。
$$保存当前进程的PID。
/proc/pid/exe是到进程可执行文件的符号链接(至少在Linux上;在AIX上,/ proc / $$ / object / a.out是到可执行文件的链接)。
readlink将输出符号链接的值。

示例:

注意:我在Ubuntu上演示了此示例,其中默认外壳程序/bin/sh是短划线的符号链接,即/bin/dash/bin/ksh是与/etc/alternatives/ksh的符号链接,这反过来又是与/bin/pdksh的符号链接。

$ chmod +x getshell.sh
$ ./getshell.sh 
/bin/pdksh
$ bash getshell.sh 
/bin/bash
$ sh getshell.sh 
/bin/dash


评论


感谢托马斯的回答。假设我们将脚本作为Node.js或Java或其他任何东西的子进程启动。我们可以启动一个“ exec”进程,然后exec将运行shell脚本吗?我问是因为我正在寻找这个问题的答案:stackoverflow.com/questions/41067872/…

–亚历山大·米尔斯(Alexander Mills)
16 Dec 9'在20:26



@AlexanderMills此答案中提到的exec()是系统调用,命令exec是内置的shell,这就是为什么您不能从Node.js或Java调用exec程序的原因。但是,任何由例如Java中的Runtime.exec()最终由exec()系统调用处理。

–托马斯·尼曼(Thomas Nyman)
16年12月11日在16:02

嗯,是的,我的确很熟悉刚才提到的Java API,我想知道是否有某种方法可以通过某种方式从Node.js调用较低级别的exec()调用。

–亚历山大·米尔斯(Alexander Mills)
16 Dec 11'在19:51

@AlexanderMills我可以想象child_process。{exec(),execFile(),spawn()}都将使用C exec()来实现(通过过程)。

–托马斯·尼曼(Thomas Nyman)
16-12-12在3:02



#2 楼

是的,它确实。顺便说一下,这不是一个愚蠢的问题。我的答案的参考在这里。
用#!开始脚本!


它叫做“ shebang”或“ bang”行。
它不过是Bash解释器的绝对路径。

它由数字符号和感叹号字符(#!)组成,后跟
解释器的完整路径,例如/ bin / bash。 。

Linux下的所有脚本都使用第一行上指定的解释器执行。
几乎所有bash脚本通常都以#!/ bin / bash开头(假设Bash已安装在/ bin中)。
这样可以确保即使在其他shell下执行脚本,也可以使用Bash来解释脚本。
shebang是由丹尼斯·里奇(Dennis Ritchie)在7版Unix和8版之间在贝尔实验室推出的。然后,它也被添加到伯克利的BSD系列中。


忽略解释器行(shebang)

如果不指定解释器行,则默认通常为/ bin / sh。但是,建议您设置#!/ bin / bash行。

评论


详细地说,内核仅知道如何执行静态链接的二进制文件以及在何处查找其他程序的解释器信息(二进制文件中的特殊字段或shebang行)。通常,执行shell脚本意味着将shebang行跟随到shell,然后将shell二进制文件中的DT_INTERP字段跟随到动态链接器。

–西蒙·里希特(Simon Richter)
13年8月21日在6:37

另请注意,这不仅限于shell脚本。所有基于文本的脚本文件都使用此文件。例如#!/ usr / bin / perl#!/ usr / local / bin / python#!/ usr / local / bin / ruby​​用于支持多个系统的另一个常见的shebang条目是使用env定位要使用的解释器,例如#!/ usr / bin / env perl#!/ usr / bin / env python

–漫步者
13年8月21日在7:31

@sambler说到env,实际上应该首选哪个? Python和Perl经常使用env,而在shellscripts上,通常会省略它,而shebang指向有问题的shell。

–polemon
13年8月21日在10:22

@polemon较少使用哪种路径,而在哪些路径上使用更多路径。在所有系统上,基本外壳都位于同一路径中。可以在不同系统上的不同位置安装最新版本的perl和python,因此使用env可以使同一shebang始终正常工作,这就是为什么env与shell脚本一起在perl和python脚本中使用更多的原因。

–漫步者
13年8月22日在8:23

env在$ PATH中查找程序有点麻烦。它没有设置环境变量,顾名思义。对于不同的用户,$ PATH可能是不同的结果。但是,它可以帮助脚本在无需修改的系统上运行,而这些修改将合理的perl解释器放在了奇怪的地方。

– John Mahowald
18年7月24日在22:08

#3 楼

实际上,如果您采取这种做法,则在shebang行中指出的可执行文件只是一个可执行文件。使用某些文本解释器作为可执行文件是有意义的,但是这不是必需的。只是为了澄清和演示,我做了一个相当无用的测试:

#!/bin/cat
useless text
more useless text
still more useless text


将该文件命名为test.txt并设置可执行位chmod u+x test.txt,然后“调用”它:./test.txt 。如预期的那样,将输出文件的内容。在这种情况下,cat不会忽略shebang线。它仅输出所有行。因此,任何有用的口译员都应该能够忽略此提示行。对于bash,perl和PHP,它只是一条注释行。所以是的,这些忽略了shebang线。

#4 楼

Linux内核的exec系统调用本身就了解shebangs(#!
我没有注意到OP询问过AIX,我要说的是我对Linux的了解,并打赌有很强的类比,或者至少满足大多数正在寻找Linux的Google员工的需求:-)
在bash上运行时:
在Linux上
./something

,这将调用路径为exec./something系统调用。 />内核的这一行在传递给exec的文件上被调用:https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25
if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))

它读取文件的第一个字节,然后将它们与#!进行比较。
如果比较结果为true,则Linux内核将对该行的其余部分进行解析,这将使用路径exec和当前文件进行另一个/usr/bin/env python调用作为第一个参数:
/usr/bin/env python /path/to/script.py

,这适用于任何使用#作为注释字符的脚本语言。
是的,您可以使无穷大循环:
printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a

Bash识别错误:
-bash: /a: /a: bad interpreter: Too many levels of symbolic links

#!恰好是人类可读的,但这不是必需的。
如果文件以不同的开头字节,则exec系统调用将使用其他处理程序。另一个最重要的内置处理程序用于ELF可执行文件:https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305检查字节7f 45 4c 46(也恰好是对于.ELF是人类可读的)。让我们通过读取/bin/ls的前四个字节(这是ELF可执行文件)来确认:
head -c 4 "$(which ls)" | hd 

输出:
00000000  7f 45 4c 46                                       |.ELF|
00000004                                                                 

因此,当内核看到这些字节时,它将使用ELF文件,将其正确放入内存,然后使用它开始新的过程。另请参阅:https://stackoverflow.com/questions/8352535/how-does-kernel-get-an-executable-binary-file-running-under-linux/31394861#31394861
最后,您可以使用binfmt_misc机制添加自己的shebang处理程序。例如,您可以为.jar文件添加自定义处理程序。该机制甚至通过文件扩展名支持处理程序。另一个应用程序是使用QEMU透明地运行不同体系结构的可执行文件。
我不认为POSIX指定shebang,但是:https://unix.stackexchange.com/a/346214/32558,尽管它确实提到了它。在基本原理部分中,以及“如果系统支持可执行脚本,则可能会发生的事情”形式。

评论


从shell运行./something不会将完整路径传递给exec,但会完全输入路径。您可以在答案中更正吗?在脚本中回显“ $ 0”,您将看到这种情况。

– AndiDog
18年7月26日在7:46

这个答案错过了“我正在使用AIX”。在这个问题上。

– JdeBP
20年6月30日在22:24

@JdeBP也是每个提出此问题的Google员工:-)

– Ciro Santilli郝海东冠状病六四事件法轮功
20年6月30日在22:27



#5 楼

根据我的收集,只要文件具有可执行位设置并被调用,内核就会分析文件头,以确定如何进行处理(据我所知,您可以通过LKM为自定义文件格式添加自定义处理程序)。如果文件看起来是带有#!的文本文件!组合开始时,将其执行分派到另一个可执行文件(通常是各种shell),该路径将在所述shebang之后的同一行中直接指定。然后,内核继续执行外壳程序并传递文件以供处理。

简而言之,使用哪个外壳程序调用脚本都没关系-内核会将执行分派到适当的位置。任一种方式。

评论


bash ./myscript.sh和./myscript.sh之间有明显的区别。

–用户
13年8月21日在9:35

您所说的“明显差异”是什么意思?

– jrara
13年8月21日在9:59

@jrara看到我的回答,“使用哪个shell调用脚本都没有关系”的说法根本就不正确。

–托马斯·尼曼(Thomas Nyman)
13年8月21日在10:33